<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tomasz</title>
    <description>The latest articles on DEV Community by Tomasz (@wrobeltomasz).</description>
    <link>https://dev.to/wrobeltomasz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3933746%2F9020a328-6799-44e6-aa7c-c124d27fe4fb.jpg</url>
      <title>DEV Community: Tomasz</title>
      <link>https://dev.to/wrobeltomasz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wrobeltomasz"/>
    <language>en</language>
    <item>
      <title>OpenSparrow v4.1 adds optional two-factor login by email</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Sat, 10 Oct 2026 08:24:06 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v41-adds-optional-two-factor-login-by-email-5024</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v41-adds-optional-two-factor-login-by-email-5024</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v4.1 adds optional two-factor login by email, streaming answers in Ask AI, and PostgreSQL views to the External API&lt;/strong&gt; — plus a security hardening pass across the write paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two-factor login, off by default
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;System → Settings → Login Security&lt;/strong&gt; gains a toggle: after a correct password, accounts with a contact email must enter a 6-digit code sent to their inbox — the pattern banking apps use, now built into your self-hosted instance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Opt-in, per account&lt;/strong&gt; — off by default; accounts without an email keep password-only login, so nobody gets locked out during rollout&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Abuse-resistant&lt;/strong&gt; — codes expire after 60 seconds, allow 5 attempts, sending is throttled per IP and username, and a delivery failure fails closed instead of skipping the factor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No new infrastructure&lt;/strong&gt; — reuses your existing cron/SMTP email settings and the contact fields from v3.3; no migration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ask AI streams its answers
&lt;/h2&gt;

&lt;p&gt;Responses arrive token by token instead of one block at the end — long analyses start appearing immediately while the model is still writing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clickable record links&lt;/strong&gt; — answers reference rows as links straight to the record&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The answer of record&lt;/strong&gt; — the streamed text is a preview; the final payload carries the cleaned-up version with markdown, links and follow-up suggestions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A working off switch&lt;/strong&gt; — the admin's Ask AI enable flag finally gates the API (403) and hides the menu button and FAB&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  External API now serves PostgreSQL views
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;System → API&lt;/strong&gt; can bind a registered PostgreSQL view — aggregates included — instead of only a raw table, which is how integrations usually want to consume data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Columns and filters are re-checked against the &lt;strong&gt;live database&lt;/strong&gt; on every save and request; an altered view answers a clean &lt;code&gt;404&lt;/code&gt;, never a &lt;code&gt;500&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Views sort by their first selected column (no guaranteed &lt;code&gt;id&lt;/code&gt;); tables keep &lt;code&gt;id DESC&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Fixed: freshly generated API keys are adopted on save instead of being regenerated on every re-save&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Also in this release
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CSV import moved to a proper service layer; cron output is plain text&lt;/li&gt;
&lt;li&gt;Version info moved from the login page to the footer&lt;/li&gt;
&lt;li&gt;New records open on the first tab&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v40-jsonb-columns-public-table-sharing-1dkk"&gt;OpenSparrow v4.0 adds a JSONB column type, public read-only table sharing, and many-to-many editing directly on the grid&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;https://opensparrow.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>opensource</category>
      <category>rag</category>
      <category>ai</category>
    </item>
    <item>
      <title>OpenSparrow v4.0: JSONB columns, public table sharing</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Wed, 07 Oct 2026 15:35:03 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v40-jsonb-columns-public-table-sharing-1dkk</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v40-jsonb-columns-public-table-sharing-1dkk</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v4.0 adds a JSONB column type, public read-only table sharing, and many-to-many editing directly on the grid&lt;/strong&gt; — plus a grid performance refactor: in-place cell updates, a side-fetch cache, and server-side sort and filters for large tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSONB columns, validated before save
&lt;/h2&gt;

&lt;p&gt;The schema editor offers &lt;code&gt;jsonb&lt;/code&gt; alongside the existing types (&lt;code&gt;includes/admin/schema.php&lt;/code&gt;). JSON entered into such a column is validated client- and server-side before it reaches SQL (&lt;code&gt;validate_jsonb_column&lt;/code&gt; in &lt;code&gt;includes/api_helpers.php&lt;/code&gt;); the value is bound with a &lt;code&gt;::jsonb&lt;/code&gt; cast through &lt;code&gt;pg_query_params&lt;/code&gt;. Workflow form template fields understand the new type too. No migration — adding the column to an existing table is the usual schema-editor &lt;code&gt;ALTER TABLE&lt;/code&gt;, done on demand per table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Public read-only table sharing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;System → Sharing&lt;/strong&gt; exposes one table through a public link — anyone with the link views the table grid without logging in, like sharing a spreadsheet on OneDrive. The page is &lt;code&gt;public/share.php&lt;/code&gt;, the data endpoint &lt;code&gt;public/api/share.php&lt;/code&gt;; config lives in &lt;code&gt;spw_config.shared_tables&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Security details that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The token is never stored in plaintext — only &lt;code&gt;token_hash&lt;/code&gt; (via &lt;code&gt;secret_hash&lt;/code&gt;), and lookups use &lt;code&gt;hash_equals&lt;/code&gt; for constant-time comparison (&lt;code&gt;SharedTokenManager&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Hidden, system, and owner-restricted tables cannot be shared; the shared schema is stripped of subtables, many-to-many relations and images&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;m2m_options&lt;/code&gt; gates &lt;code&gt;other_table&lt;/code&gt;, so a share link cannot be pointed at an unrelated table; stale entries are pruned automatically on save&lt;/li&gt;
&lt;li&gt;The page sends &lt;code&gt;X-Robots-Tag: noindex, nofollow&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The grid, faster
&lt;/h2&gt;

&lt;p&gt;Four changes shipped together (&lt;code&gt;includes/frontapi/list.php&lt;/code&gt;, &lt;code&gt;public/assets/js/grid/&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Row cap&lt;/strong&gt;: full-table fetches carry an explicit cap — &lt;code&gt;MAX_LIST_ROWS&lt;/code&gt; (default 1000, overridable per table via &lt;code&gt;initial_limit&lt;/code&gt; in Schema → Table Properties). No loader can request an unbounded set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Side-fetch cache&lt;/strong&gt;: the four auxiliary loaders (comment counts, subtable counts, m2m rows, image rows) fetch once per page signature and re-apply from their stores on re-render — two renders in a row don't refetch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-place cell updates&lt;/strong&gt;: saving a cell mutates the local dataset and re-renders the grid — no full &lt;code&gt;loadTable&lt;/code&gt; round-trip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid client/server view&lt;/strong&gt;: if the response is truncated, the grid switches to server-side search, sort, and column filters — one combined request per change; "Load more" chunks continue the server ordering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of that, the grid supports &lt;strong&gt;multi-column sorting&lt;/strong&gt; (up to three rules with priority icons), and virtual columns gained &lt;strong&gt;conditional icons&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Many-to-many editing on the grid
&lt;/h2&gt;

&lt;p&gt;M2M relations are now edited in a popover picker right on the grid, backed by two new API actions: &lt;code&gt;m2m_sync&lt;/code&gt; (writes, audited like any record change) and &lt;code&gt;m2m_options&lt;/code&gt; (reads, access-gated). The popover shares the same 1-second hover delay as the image preview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backup retention, calendar week view, config autosave
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backup Tables → Global Settings&lt;/strong&gt; gained retention: keep the newest N backups, drop backups older than X days (both optional), a list of stored backups, and on-demand cleanup. Retention is applied automatically after each backup run (&lt;code&gt;backup_apply_retention&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;calendar&lt;/strong&gt; got a month/week view toggle — the week view renders an hourly grid with an all-day bar, and events move in both.&lt;/li&gt;
&lt;li&gt;The admin &lt;strong&gt;"Save config" button is gone&lt;/strong&gt;: configuration autosaves with optimistic versioning. If another admin saved in the meantime, you get a conflict notice instead of a silent overwrite.&lt;/li&gt;
&lt;li&gt;Schema and Views editors were restyled to the common section-card layout.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v39-makes-the-board-and-calendar-fully-touch-friendly-21ig"&gt;OpenSparrow v3.9 — touch drag &amp;amp; drop for board and calendar, and a demo-free setup wizard&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;https://opensparrow.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>OpenSparrow v3.9 - makes the board and calendar fully touch-friendly</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Mon, 28 Sep 2026 15:30:03 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v39-makes-the-board-and-calendar-fully-touch-friendly-21ig</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v39-makes-the-board-and-calendar-fully-touch-friendly-21ig</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v3.9 makes the board and calendar fully touch-friendly and moves the CRM demo out of the setup wizard.&lt;/strong&gt; A shared pointer-drag shim brings drag &amp;amp; drop to touch devices; the demo is now an opt-in in &lt;strong&gt;Admin → Demo&lt;/strong&gt; after first login.&lt;/p&gt;

&lt;h2&gt;
  
  
  Touch drag &amp;amp; drop for board and calendar
&lt;/h2&gt;

&lt;p&gt;HTML5 drag &amp;amp; drop never fires &lt;code&gt;dragstart&lt;/code&gt; / &lt;code&gt;dragover&lt;/code&gt; / &lt;code&gt;drop&lt;/code&gt; for touch pointers — dragging a board card on a phone did nothing. Workarounds (long-press timers, hijacked &lt;code&gt;touchmove&lt;/code&gt;) fail: the browser decides the scroll-vs-drag gesture before JavaScript can react.&lt;/p&gt;

&lt;p&gt;v3.9 fixes this with CSS, not JavaScript: the shim (&lt;code&gt;public/assets/js/util/touch-dnd.js&lt;/code&gt;) sets &lt;code&gt;touch-action&lt;/code&gt; at wiring time — &lt;code&gt;pan-y&lt;/code&gt; on board cards (horizontal drags, vertical swipes scroll) and &lt;code&gt;none&lt;/code&gt; on calendar chips. The browser routes the gesture natively; no timers, no hijacked scrolling.&lt;/p&gt;

&lt;p&gt;Drags start by &lt;strong&gt;movement, not hold time&lt;/strong&gt; — a &amp;gt;12 px, direction-aware slop keeps taps as clicks. A ghost follows the finger, drop targets highlight, and &lt;code&gt;pointercancel&lt;/code&gt; cleans up. Gated on &lt;code&gt;pointerType === 'touch'&lt;/code&gt;, the shim leaves desktop HTML5 DnD untouched; both paths call the same move function (&lt;code&gt;moveCard&lt;/code&gt;, &lt;code&gt;moveEventTo&lt;/code&gt;) — one source of truth for optimistic update, API call and rollback. It wires only where modules gate on &lt;code&gt;canEdit&lt;/code&gt;. A same-pass fix puts the &lt;code&gt;drop-target&lt;/code&gt; class on the lane element itself, so the highlight renders.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup wizard no longer installs the demo
&lt;/h2&gt;

&lt;p&gt;The demo checkbox is gone; the wizard now does one thing: schema, system tables, migrations, and the first admin account with a one-time random password. The demo itself is untouched — after first login, &lt;strong&gt;Admin → Demo&lt;/strong&gt; offers every part (sample tables, dashboards, board, RAG knowledge base, demo accounts) as a reversible opt-in. &lt;code&gt;public/setup_api.php&lt;/code&gt; no longer fakes a logged-in admin session mid-setup, and the four &lt;code&gt;setup.*demo*&lt;/code&gt; i18n keys were dropped from all 20 language files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smaller interface changes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nav menu items&lt;/strong&gt; got thin &lt;code&gt;1px&lt;/code&gt; borders, stronger on hover and active — structure without visual noise&lt;/li&gt;
&lt;li&gt;The sidebar &lt;strong&gt;collapse icon&lt;/strong&gt; right-aligns to the far edge of the menu, where it reads as "collapse this"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Upgrade notes
&lt;/h2&gt;

&lt;p&gt;No database migration, no removed configuration keys; the release migration only deletes the unused &lt;code&gt;public/mock.html&lt;/code&gt;. One caveat: emulated pointers bypass native scrolling, so the shim was validated on real devices before shipping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v38-roadmap-gantt-module-and-new-style-grid-4mei"&gt;OpenSparrow v3.8 — a Roadmap (Gantt) module and a spreadsheet-style grid&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;https://opensparrow.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>nocode</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>OpenSparrow v3.8 - Roadmap (Gantt) module and new style grid</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Tue, 22 Sep 2026 14:16:05 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v38-roadmap-gantt-module-and-new-style-grid-4mei</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v38-roadmap-gantt-module-and-new-style-grid-4mei</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v3.8 ships a brand-new Roadmap (Gantt) module and gives the record grid a long-overdue new-style facelift.&lt;/strong&gt; The roadmap module turns any schema table into a read-only Gantt timeline — multiple roadmaps, category color chips, milestone markers — with zero new database objects. The rest of the release polishes what you look at all day: crisper table borders, a relocated sidebar toggle, refreshed branding and better color contrast on enum dropdowns. Below is a breakdown of what changed and why it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roadmap (Gantt) module
&lt;/h2&gt;

&lt;p&gt;The headline feature lives in &lt;code&gt;Admin → Data Management → Roadmap&lt;/code&gt;. You define one or more roadmaps, each bound to a schema table through a set of column mappings: which column holds the title, which ones the start and end dates, optionally a category column, a progress column and card columns for the row details. Everything is configuration in the existing &lt;code&gt;spw_config&lt;/code&gt; store — there is no new table, no migration, nothing to run after upgrading.&lt;/p&gt;

&lt;p&gt;On the frontend each roadmap renders as a read-only Gantt timeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A month grid with quarter shading and prev/next navigation to scroll through time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Milestone markers&lt;/strong&gt; for rows without an end date — one-off deadlines show up as distinct markers instead of phantom bars&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;category filter bar&lt;/strong&gt; — colored chips with a legend dot per category; click a chip to toggle the whole category on or off, and the filter state is remembered&lt;/li&gt;
&lt;li&gt;A per-roadmap color for the bars, plus configurable card columns showing extra data when you inspect a row&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbarf73ijila2ex7v5z34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbarf73ijila2ex7v5z34.png" alt="New grid style" width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Access control follows the existing per-user scope model rather than inventing a new one. A new &lt;code&gt;roadmaps&lt;/code&gt; scope gates the menu entries and the front API, and the bound table must additionally be within the user's table access — the same empty-grant-list-means-unrestricted semantics as every other scope. Granting a user a roadmap does not grant its table.&lt;/p&gt;

&lt;p&gt;The CRM demo dataset gained a &lt;code&gt;projects&lt;/code&gt; table with sample rows so you can seed a working roadmap in seconds, the UI strings are translated into all 20 locales, and the new endpoints are pinned by guard tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The grid now looks like a spreadsheet
&lt;/h2&gt;

&lt;p&gt;If you spend your day inside the record grid, this is the change you'll notice first. The grid and view tables dropped the zebra striping in favor of new style cell borders every cell gets a border, the header row sits on a light background, and hover states highlight individual cells instead of whole rows. The result reads like a spreadsheet: dense, regular, easier to scan column-by-column. All colors come from the existing design tokens, so custom themes keep working.&lt;/p&gt;

&lt;p&gt;A static design reference for the new look ships as &lt;code&gt;public/mock.html&lt;/code&gt; — it isn't referenced by the application and is safe to delete from production deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smaller interface changes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sidebar toggle relocated&lt;/strong&gt; — the desktop collapse toggle moved from the header to the bottom of the menu, where it belongs; the hamburger stays in the header on mobile&lt;/li&gt;
&lt;li&gt;Menu-list nav links now render at 14px &lt;code&gt;font-sans&lt;/code&gt;, aligning with the grid typography&lt;/li&gt;
&lt;li&gt;Branding assets were refreshed — a new &lt;code&gt;logo.png&lt;/code&gt; and a favicon that dropped from 207 KB to under 3 KB&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fixed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Enum dropdowns keep readable text color via &lt;strong&gt;YIQ contrast&lt;/strong&gt; on both the grid and the edit/create form — previously a custom enum color could render white-on-light or dark-on-dark option text. The contrast is computed server-side and applied consistently&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs.js&lt;/code&gt; inconsistencies across admin modules were repaired, along with a broken Polish string in &lt;code&gt;docs-strings.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The cron, anonymization and ETL log docs now describe the status values correctly as &lt;code&gt;running / success / error&lt;/code&gt; (they were documented as &lt;code&gt;ok&lt;/code&gt;), in &lt;code&gt;docs/DATABASE.md&lt;/code&gt; and in the column comments emitted by the system-tables DDL&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Upgrade note
&lt;/h2&gt;

&lt;p&gt;No database migration and no configuration keys are removed by this release. Roadmap configuration lives in the existing &lt;code&gt;spw_config&lt;/code&gt; store under the &lt;code&gt;roadmap&lt;/code&gt; key; there is nothing to run or clean up after upgrading. For per-user access, remember the &lt;code&gt;roadmaps&lt;/code&gt; scope is independent — users also need table access to see any roadmap content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v37-brings-an-automation-email-queue-to-the-admin-panel-and-unifies-the-entire-admin-43d8"&gt;OpenSparrow v3.7 — Automation Email Queue and a Unified Admin UI&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;https://opensparrow.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>postgres</category>
    </item>
    <item>
      <title>OpenSparrow v3.7 - brings an automation email queue to the admin panel and unifies the entire admin UI</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Fri, 18 Sep 2026 05:58:12 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v37-brings-an-automation-email-queue-to-the-admin-panel-and-unifies-the-entire-admin-43d8</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v37-brings-an-automation-email-queue-to-the-admin-panel-and-unifies-the-entire-admin-43d8</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v3.7 brings an automation email queue to the admin panel and unifies the entire admin UI around a single section-card pattern.&lt;/strong&gt; The email queue gives admins full visibility and control over outgoing automation emails — filter, requeue, bulk delete, purge — while the rest of the release is a consistent overhaul of how admin screens are built: one card style, one width, one typography scale, one statistics tile pattern. Below is a breakdown of what changed and why it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automation email queue
&lt;/h2&gt;

&lt;p&gt;A new section in &lt;code&gt;Admin → System → Cron&lt;/code&gt; lists the queued automation emails stored in the existing &lt;code&gt;spw_automation_emails&lt;/code&gt; table. Until now those rows were written by the notification cron but invisible from the UI — if a message bounced or sat undelivered, there was nowhere to see it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter the queue by status — pending / sent / error — with live per-status counters&lt;/li&gt;
&lt;li&gt;Bulk requeue resets the attempts counter and error message, so failed sends retry cleanly&lt;/li&gt;
&lt;li&gt;Bulk delete works on up to 500 rows at once&lt;/li&gt;
&lt;li&gt;Purge by status, optionally limited to entries older than a configurable retention window&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The queue tab reports a missing table instead of failing, so an instance that never ran email automations degrades gracefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAG document preview
&lt;/h2&gt;

&lt;p&gt;A Preview button in the Centrum AI documents list opens a modal with the stored document content — filename, tags, size and dates included — so you can inspect what the RAG pipeline actually chunked without downloading the file. The rechunk action now shows success feedback, and the documents table respects container width with vertically stacked action buttons on narrow screens.&lt;/p&gt;

&lt;h2&gt;
  
  
  The RAG section is now Centrum AI
&lt;/h2&gt;

&lt;p&gt;The admin section formerly known as RAG is renamed to &lt;strong&gt;Centrum AI&lt;/strong&gt; across the sidebar, breadcrumbs, demo copy and guidance docs. The RAG settings fields gained explanatory tooltips covering context-file limits, upload size and timeout constraints — previously you had to check the docs to know what a field accepted.&lt;/p&gt;

&lt;h2&gt;
  
  
  One admin UI pattern instead of twenty
&lt;/h2&gt;

&lt;p&gt;The bulk of the release is invisible until you open two tabs side by side. Every settings form, data table and log in the admin panel now renders inside a &lt;code&gt;buildSectionCard&lt;/code&gt; section with a consistent header style:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Section cards are never nested — one card is one section, a tab is a flat sequence of cards in reading order&lt;/li&gt;
&lt;li&gt;All settings tabs share one width via the &lt;code&gt;.admin-page&lt;/code&gt; wrapper; per-panel &lt;code&gt;max-width&lt;/code&gt; inline styles were removed&lt;/li&gt;
&lt;li&gt;Statistics and log tabs (External API Usage, Click Statistics, Cron email queue, Users) follow the same tile-grid pattern as Centrum AI → Query Statistics&lt;/li&gt;
&lt;li&gt;Typography was unified to three sizes and two weights via CSS tokens; &lt;code&gt;.adm-sec-hdr&lt;/code&gt; styling now lives in the stylesheet instead of inline overrides&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fixed
&lt;/h2&gt;

&lt;p&gt;Admin tab renderers no longer wipe section descriptions when re-rendering a tab — content is now rendered into the inner content div instead of replacing the whole panel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade note
&lt;/h2&gt;

&lt;p&gt;No database migration and no configuration keys are removed by this release. The email queue operates on the existing &lt;code&gt;spw_automation_emails&lt;/code&gt; table (created by earlier releases); if the table does not exist, the queue tab says so instead of erroring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v36-adds-an-external-api-module-dj1"&gt;OpenSparrow v3.6 — External API Module with Encrypted Read-Only Keys&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;https://opensparrow.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>nocode</category>
      <category>productivity</category>
      <category>database</category>
    </item>
    <item>
      <title>OpenSparrow v3.6 adds an External API module</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Tue, 08 Sep 2026 15:41:24 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v36-adds-an-external-api-module-dj1</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v36-adds-an-external-api-module-dj1</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v3.6 adds an External API module that lets admins expose table data to external services through read-only, encrypted API keys.&lt;/strong&gt; Each key is bound to a single table with a fixed column set, server-side filters and a row limit, and is served by a sessionless JSON endpoint that accepts nothing from the client except the key itself. Below is a breakdown of what changed and why it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  External API module
&lt;/h2&gt;

&lt;p&gt;A new &lt;code&gt;Admin → System → API&lt;/code&gt; tab lets admins define read-only API keys. Each definition is bound to one schema table, a chosen set of columns, fixed server-side filters and a row limit, so the data an external service can see is decided entirely by the admin — never by the caller.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keys are stored encrypted (&lt;code&gt;key_enc&lt;/code&gt;) plus an HMAC &lt;code&gt;key_hash&lt;/code&gt; for constant-time lookup, and are never returned to the browser after generation&lt;/li&gt;
&lt;li&gt;A new or regenerated key is generated server-side and shown exactly once in a modal&lt;/li&gt;
&lt;li&gt;Filter values are type-checked against the column's schema type on save, so a stored filter can't 500 at query time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A sessionless JSON endpoint
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;public/api/external.php&lt;/code&gt; is the single endpoint. External services authenticate with an &lt;code&gt;Authorization: Bearer &amp;lt;key&amp;gt;&lt;/code&gt; header and receive JSON rows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The endpoint accepts no table, column or filter names from the client — everything comes from the config&lt;/li&gt;
&lt;li&gt;Hidden and system (&lt;code&gt;spw_&lt;/code&gt;) tables are refused, both on save and at request time&lt;/li&gt;
&lt;li&gt;Rate limiting is enforced per key and per IP, answering &lt;code&gt;429&lt;/code&gt; with a &lt;code&gt;Retry-After&lt;/code&gt; header&lt;/li&gt;
&lt;li&gt;Responses are &lt;code&gt;401&lt;/code&gt; (missing/bad key), &lt;code&gt;403&lt;/code&gt; (disabled), &lt;code&gt;404&lt;/code&gt; (configured table gone) and &lt;code&gt;429&lt;/code&gt; (rate limited)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usage statistics
&lt;/h2&gt;

&lt;p&gt;A new &lt;code&gt;spw_external_api_log&lt;/code&gt; table records each successful request — API, table, rows returned and duration — with a stats/log view and a purge action in the admin module, so you can see exactly how your keys are being used.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;includes/db.php&lt;/code&gt; gained &lt;code&gt;sys_table_prefix()&lt;/code&gt; / &lt;code&gt;is_system_table()&lt;/code&gt; helpers so the endpoint can refuse system tables.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;includes/crypto.php&lt;/code&gt; gained &lt;code&gt;secret_hash()&lt;/code&gt; (HMAC-SHA256) so keys can be matched without decrypting every entry.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fixed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;nginx and Apache configs now forward the &lt;code&gt;Authorization&lt;/code&gt; header to PHP (&lt;code&gt;fastcgi_param HTTP_AUTHORIZATION&lt;/code&gt; / &lt;code&gt;SetEnvIf&lt;/code&gt;), so Bearer auth works out of the box instead of silently 401ing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Upgrade note
&lt;/h2&gt;

&lt;p&gt;No database migration and no configuration keys are removed by this release. The &lt;code&gt;external_api&lt;/code&gt; config key is created on first save; an unknown key is ignored, so the document upgrades itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v35-login-language-selector-searchable-fk-pickers-notification-polish-1089"&gt;OpenSparrow v3.5 — Language Selector, Searchable FK Pickers and Notification Timestamps&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;https://opensparrow.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>php</category>
      <category>postgres</category>
      <category>webdev</category>
    </item>
    <item>
      <title>OpenSparrow v3.5 - Login language selector, searchable FK pickers &amp; notification polish</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Fri, 04 Sep 2026 15:13:20 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v35-login-language-selector-searchable-fk-pickers-notification-polish-1089</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v35-login-language-selector-searchable-fk-pickers-notification-polish-1089</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v3.5 is a usability release that adds a language selector to the login page, searchable foreign-key pickers, and notification timestamps, while unifying the notifications dropdown with the shared panel style.&lt;/strong&gt; This update makes the app friendlier for international users, speeds up data entry on long foreign-key lists, and tidies a few small UI details. Below is a breakdown of what changed and why it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Language selector on the login page
&lt;/h2&gt;

&lt;p&gt;Users can now pick their locale before signing in. The login form gains a language &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; populated from the available locales, and the &lt;code&gt;&amp;lt;html lang&amp;gt;&lt;/code&gt; attribute follows the active locale so screen readers and browsers render the page in the right language from the very first screen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Locale is chosen before authentication, so the whole session starts in the user's language&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;html lang&amp;gt;&lt;/code&gt; attribute now tracks the active locale instead of a hardcoded value&lt;/li&gt;
&lt;li&gt;Selection is driven by &lt;code&gt;I18n::availableLanguageMeta()&lt;/code&gt;, so new locales appear automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Searchable foreign-key pickers
&lt;/h2&gt;

&lt;p&gt;Edit and create forms replace the plain &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; on foreign-key fields with a searchable input backed by a &lt;code&gt;&amp;lt;datalist&amp;gt;&lt;/code&gt;. Long FK lists are now filterable by typing instead of scrolling through a dropdown.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New &lt;code&gt;public/assets/js/edit/fk-search.js&lt;/code&gt; wires up the search behaviour&lt;/li&gt;
&lt;li&gt;Typing filters the datalist; the selected value is synced to a hidden field carrying the real FK id&lt;/li&gt;
&lt;li&gt;Blurring with an unmatched value restores the original label, so invalid selections can't slip through&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Notification timestamps
&lt;/h2&gt;

&lt;p&gt;Each item in the notifications dropdown now shows its &lt;code&gt;created_at&lt;/code&gt; time, formatted with the browser's locale. You can tell at a glance how old a notification is.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub link in the footer
&lt;/h2&gt;

&lt;p&gt;A GitHub lockup badge now links to the project repository from the footer, so the source is one click away from anywhere in the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The notifications dropdown was unified with the shared &lt;code&gt;bp-panel&lt;/code&gt; style (header, close button, overlay) instead of its own bespoke markup.&lt;/li&gt;
&lt;li&gt;Notes UI strings are now translated into all 19 locales.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fixed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;#debug&lt;/code&gt; bar no longer flashes before JS hides it on page load — it is now hidden inline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Upgrade note
&lt;/h2&gt;

&lt;p&gt;No database migration and no configuration keys are removed by this release. Upgrading is a drop-in replacement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v34-replaces-the-bundled-icon-set-with-material-symbols-outlined-and-adds-a-3jjj"&gt;OpenSparrow v3.4 — Material Symbols Outlined and a Searchable Icon Picker&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;https://opensparrow.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>nocode</category>
      <category>postgres</category>
      <category>javascript</category>
    </item>
    <item>
      <title>OpenSparrow v3.4 — replaces the bundled icon set with Material Symbols Outlined and adds a searchable icon picker</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Wed, 02 Sep 2026 06:30:41 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v34-replaces-the-bundled-icon-set-with-material-symbols-outlined-and-adds-a-3jjj</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v34-replaces-the-bundled-icon-set-with-material-symbols-outlined-and-adds-a-3jjj</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v3.4 is a design-focused release that replaces the bundled icon set with Material Symbols Outlined and adds a searchable icon picker to the admin panel.&lt;/strong&gt; This update modernizes the visual language across the whole application, gives admins a fast way to find the right icon, and cleans up a handful of smaller UI details. Below is a breakdown of what changed and why it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Material Symbols Outlined
&lt;/h2&gt;

&lt;p&gt;The bundled icon set has been replaced with Google's Material Symbols Outlined. The new set lives in &lt;code&gt;public/assets/icons/material/&lt;/code&gt; and carries the full collection — &lt;strong&gt;3,899 SVG files&lt;/strong&gt; at optical size 24, normalized to 48×48 so they match the intrinsic size of the PNG icons they sit next to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7cp7sl6myne0faxsa4ma.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7cp7sl6myne0faxsa4ma.jpg" alt="Icon picker screenshot" width="800" height="589"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;84 files removed from &lt;code&gt;public/assets/icons/&lt;/code&gt; (83 PNG plus &lt;code&gt;chevron-down-white.svg&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The dropdown arrow on &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; elements is now an inline data URI in &lt;code&gt;styles.css&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Eight PNG icons the system still references by name (&lt;code&gt;book_3s&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;, &lt;code&gt;folder_zip&lt;/code&gt;, &lt;code&gt;grid_on&lt;/code&gt;, &lt;code&gt;notifications&lt;/code&gt;, &lt;code&gt;picture_as_pdf&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;, &lt;code&gt;settings&lt;/code&gt;) stay where they are&lt;/li&gt;
&lt;li&gt;Generated manifests (&lt;code&gt;index.json&lt;/code&gt;, &lt;code&gt;tags.json&lt;/code&gt;, &lt;code&gt;README.txt&lt;/code&gt;) ship alongside the SVGs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Searchable icon picker
&lt;/h2&gt;

&lt;p&gt;The icon field in the admin now gets a proper picker instead of a bare text input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Matches icon names and the full Google tag list&lt;/li&gt;
&lt;li&gt;Understands common Polish words (e.g. "ciężarówka" → local shipping)&lt;/li&gt;
&lt;li&gt;Category chips for quick filtering&lt;/li&gt;
&lt;li&gt;Remembers recently picked icons in the browser&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Upgrade note: icon paths live in the database
&lt;/h2&gt;

&lt;p&gt;This is the one thing to know before upgrading. Icon paths are stored in the database, not in code — the &lt;code&gt;menu_icon&lt;/code&gt; keys of the dashboard, calendar, files, board, views and workflows config, the per-table icon in the schema config, and the printout icons.&lt;/p&gt;

&lt;p&gt;A stored path naming one of the removed files stays valid as far as validation is concerned and renders as a broken image — nothing rewrites those values automatically. Repoint them in the admin with the Browse picker. 79 of the 84 removed names have an identically named &lt;code&gt;.svg&lt;/code&gt; under &lt;code&gt;assets/icons/material/&lt;/code&gt;, so &lt;code&gt;assets/icons/NAME.png&lt;/code&gt; usually becomes &lt;code&gt;assets/icons/material/NAME.svg&lt;/code&gt;. The exceptions are &lt;code&gt;calendar.png&lt;/code&gt; (use &lt;code&gt;calendar_month.svg&lt;/code&gt;) and &lt;code&gt;folder_zip_blue.png&lt;/code&gt;, &lt;code&gt;grid_on_blue.png&lt;/code&gt;, &lt;code&gt;picture_as_pdf_blue.png&lt;/code&gt;, which have no direct counterpart.&lt;/p&gt;

&lt;p&gt;No database migration and no configuration keys are removed by this release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also in this release
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Removed the GitHub link from the login page&lt;/li&gt;
&lt;li&gt;Fixed demo image seeding; long lines wrapped; Files menu icon unified&lt;/li&gt;
&lt;li&gt;Updated grid action icon names in the admin docs&lt;/li&gt;
&lt;li&gt;Refreshed module demo video links and images in the README&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v33-click-statistics-production-readiness-check-and-deployment-hardening-170h"&gt;OpenSparrow v3.3 — Click Statistics, Production Readiness Checks, and Deployment Hardening&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;https://opensparrow.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>nocode</category>
    </item>
    <item>
      <title>MatrAIx consists of 8.3 billion agent-persons who statistically represent the entire human population</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Fri, 28 Aug 2026 20:52:27 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/matraix-consists-of-83-billion-agent-persons-who-statistically-represent-the-entire-human-5n6</link>
      <guid>https://dev.to/wrobeltomasz/matraix-consists-of-83-billion-agent-persons-who-statistically-represent-the-entire-human-5n6</guid>
      <description>&lt;p&gt;It is an open-source research community that has created an infrastructure for simulating user behavior. At its core is a database of &lt;strong&gt;8.3 billion virtual agents&lt;/strong&gt; (personas) that statistically represent the entire human population, allowing digital products and AI to be tested without involving real people.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How are users created?&lt;/strong&gt;&lt;br&gt;
Personas are created using a hybrid approach—combining real-world data (Wikipedia, surveys) and synthetic data (generated by AI). Each of the 8.3 billion personas has 1,290 detailed traits (demographics, psychology, skills) and is then materialized as an LLM agent that makes decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you use them technically?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resources: Download a ready-made set of 1 million personas from Hugging Face (or the full 8B dataset).&lt;/li&gt;
&lt;li&gt;Requirements: You’ll need Docker, uv (Python), Node.js, and API keys (primarily from Anthropic).&lt;/li&gt;
&lt;li&gt;Setup: Clone the repo, install dependencies, and download the data.&lt;/li&gt;
&lt;li&gt;Running: Create test tasks (surveys, chat, browser, app) and run them on individual personas, in batch mode, or via the Playground GUI.&lt;/li&gt;
&lt;li&gt;Applications: Market research, chatbot testing, website usability assessment, and evaluation of AI models for different user groups. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The developers emphasize that MatrAIx is intended for preliminary testing and hypothesis evaluation, but does not fully replace final testing with real people. An interesting application is simulating user behavior in applications (Web &amp;amp; App UI/UX): Agents interact with websites or apps (by controlling the browser or default API) to test purchase paths and the intuitiveness of the interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does the trained data look like (data structure)?&lt;/strong&gt;&lt;br&gt;
It consists of structured attribute profiles (JSON / Parquet). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4qyqmw4m9yz39niqgzqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4qyqmw4m9yz39niqgzqn.png" alt="json example" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before an agent is used, its attributes are dynamically converted into a system prompt for the LLM.&lt;/p&gt;

&lt;p&gt;On the project website, you'll find something interesting: &lt;strong&gt;graphical interface&lt;/strong&gt; at &lt;a href="https://matraix.ai/playground/" rel="noopener noreferrer"&gt;matraix.ai/playground&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You select a persona (e.g., from the Persona-1M database based on filters such as age, country, and education). &lt;/li&gt;
&lt;li&gt;You choose one of 8 tasks (e.g., Web Browsing or Survey). &lt;/li&gt;
&lt;li&gt;You run the simulation and observe in real time (or analyze in the summary) how that profile performs the assigned task.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Website: &lt;a href="https://matraix.ai/" rel="noopener noreferrer"&gt;matraix.ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you think of this project?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;In what areas can this project be used?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>datascience</category>
      <category>llm</category>
      <category>productivity</category>
    </item>
    <item>
      <title>OpenSparrow v3.3 — Click Statistics, Production Readiness Check, and Deployment Hardening</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Thu, 20 Aug 2026 18:25:47 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v33-click-statistics-production-readiness-check-and-deployment-hardening-170h</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v33-click-statistics-production-readiness-check-and-deployment-hardening-170h</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v3.3 is a stability‑focused and deployment‑focused release that brings real‑world operational visibility, a production‑readiness checklist, and a full hardening pass across environment variables and configuration defaults.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This update introduces an optional Click Statistics module, expands the Admin Health Check into a proper production‑readiness validator, and tightens deployment settings for anyone running OpenSparrow outside a local dev box. Below is a detailed breakdown of what changed, why it matters, and how it improves day‑to‑day operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Click Statistics
&lt;/h2&gt;

&lt;p&gt;A new optional module — off by default, and &lt;em&gt;off&lt;/em&gt; genuinely means off. &lt;br&gt;
When the module disabled, no collector script is emitted, nothing is downloaded, and the endpoint returns 204 without writing even if a page stays open across a toggle‑off.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F450jzsqt5yw1ewzv4o3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F450jzsqt5yw1ewzv4o3o.png" alt="Admin click statistic module" width="800" height="767"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Records who clicked what, when, on which page, and optionally the table/record in context
(“Record Table And Record” can be turned off to keep entries to just user/time/element)&lt;/li&gt;
&lt;li&gt;Log tab: recent clicks newest‑first, filterable by element and user, with a &lt;strong&gt;Top Elements&lt;/strong&gt; rollup of the 20 most‑clicked elements&lt;/li&gt;
&lt;li&gt;Retention: “Delete Automatically After N days” (default 90, &lt;code&gt;0 = keep forever&lt;/code&gt;) enforced by the notifications cron so the table doesn’t grow unbounded&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Admin Health Check: Production Readiness tab
&lt;/h2&gt;

&lt;p&gt;Health Check now includes a dedicated tab answering &lt;strong&gt;is this deployment actually production‑ready?&lt;/strong&gt; instead of just “is the database reachable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd3ai5jna2i2qnlrcdnle.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd3ai5jna2i2qnlrcdnle.png" alt="Admin production verify" width="800" height="674"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It validates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;APP_ENV&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;demo mode being off&lt;/li&gt;
&lt;li&gt;secure cookies&lt;/li&gt;
&lt;li&gt;HTTPS (including behind reverse proxies via &lt;code&gt;X-Forwarded-Proto&lt;/code&gt; / &lt;code&gt;CF-Visitor&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;display_errors&lt;/code&gt; off&lt;/li&gt;
&lt;li&gt;Argon2id availability&lt;/li&gt;
&lt;li&gt;minimum password length of 12&lt;/li&gt;
&lt;li&gt;API rate limiting configuration&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SESSION_SAMESITE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;trusted‑proxy‑header configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Existing checks were refreshed as well — minimum supported PHP version now correctly requires &lt;strong&gt;8.4&lt;/strong&gt;, matching the rest of the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment hardening
&lt;/h2&gt;

&lt;p&gt;A broad pass through &lt;code&gt;.env.example&lt;/code&gt; and &lt;code&gt;includes/config.php&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every environment variable is now documented
&lt;/li&gt;
&lt;li&gt;numeric config values are clamped to sane ranges
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;APP_TIMEZONE&lt;/code&gt; and &lt;code&gt;SESSION_SAMESITE&lt;/code&gt; are validated instead of trusted blindly
&lt;/li&gt;
&lt;li&gt;new settings cover:
&lt;code&gt;APP_URL&lt;/code&gt;, &lt;code&gt;STORAGE_PATH&lt;/code&gt;, &lt;code&gt;SESSION_COOKIE_NAME&lt;/code&gt;, &lt;code&gt;DB_SSLMODE&lt;/code&gt;, API rate limiting,
statement/SMTP/HTTP client timeouts, session idle timeout, Argon2 tuning,
and a trusted‑proxy IP list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional hardening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API throttle now fails open (instead of blocking all requests) if its state store becomes unwritable
&lt;/li&gt;
&lt;li&gt;libpq connection‑info values are quoted
&lt;/li&gt;
&lt;li&gt;CSP report URI restricted to same‑origin&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Also in this release
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flujyvlqyldk6onjwtwz5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flujyvlqyldk6onjwtwz5.png" alt="Users information" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Optional first name, last name, email, and phone fields on admin user accounts (informational only — not used for login, ownership, or notifications)&lt;/li&gt;
&lt;li&gt;Logo and favicon refreshed; login/admin brand text sized down to match&lt;/li&gt;
&lt;li&gt;Large internal cleanup:
PHP/JS variable names expanded from abbreviations to full words,
public API endpoints moved behind typed controllers (&lt;code&gt;App\Controller&lt;/code&gt;),
and &lt;code&gt;die()&lt;/code&gt; / &lt;code&gt;exit()&lt;/code&gt; replaced with a typed exception hierarchy
— no behavior change, but relevant if you track the codebase&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v32-per-user-access-control-materialized-views-in-rag-and-a-business-design-refresh-333o"&gt;OpenSparrow v3.2 — Per‑User Access Control, Materialized Views in RAG, and a Business Design Refresh&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;https://opensparrow.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>lowcode</category>
      <category>postgres</category>
      <category>devops</category>
    </item>
    <item>
      <title>OpenSparrow v3.2 - Per-User Access Control, Materialized Views in RAG, and a Business Design Refresh</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Thu, 13 Aug 2026 14:22:39 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v32-per-user-access-control-materialized-views-in-rag-and-a-business-design-refresh-333o</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v32-per-user-access-control-materialized-views-in-rag-and-a-business-design-refresh-333o</guid>
      <description>&lt;p&gt;&lt;strong&gt;OpenSparrow v3.2 is a security‑focused and consistency‑focused release that strengthens access boundaries, improves AI‑driven aggregate queries, and unifies the entire admin and frontend experience under one design system.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This update introduces per‑user access control across all major scopes, brings materialized‑view support to RAG aggregate queries, and delivers a full visual refresh that aligns every UI surface with the new Business design language.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe165ztp978f8mmeme9a6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe165ztp978f8mmeme9a6.gif" alt="Board view" width="720" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below is a detailed breakdown of the changes, including how they work, why they matter, and what they unlock for real deployments.&lt;/p&gt;




&lt;h2&gt;
  
  
  Per-user access control
&lt;/h2&gt;

&lt;p&gt;New &lt;strong&gt;Users → Access&lt;/strong&gt; tab. Each user gets independent allow‑lists across five scopes — tables, views, printouts, boards, workflows — stored as &lt;code&gt;user_table_access&lt;/code&gt; in config.&lt;br&gt;&lt;br&gt;
The default is unrestricted: an absent or empty list means &lt;strong&gt;“no restriction”&lt;/strong&gt;, not &lt;strong&gt;“no access”&lt;/strong&gt;. To fully cut a user off, deactivate the account instead.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enforced at the API boundary by default, not just hidden in the UI — &lt;code&gt;os_api_action()&lt;/code&gt; / &lt;code&gt;os_api_dispatch()&lt;/code&gt; gate table, view, print, board, and workflow endpoints, and FK/file/comment/mass‑edit/data‑cleanup endpoints were extended to respect the same restrictions
&lt;/li&gt;
&lt;li&gt;Granting a board or workflow does not implicitly grant the tables it touches — a board whose table isn’t granted won’t show up, and a workflow drops if any step targets a table the user can’t reach
&lt;/li&gt;
&lt;li&gt;Hidden tables (no menu entry, no grid) can’t be ticked and are granted automatically
&lt;/li&gt;
&lt;li&gt;Delegated FK lookups and the schema endpoint are now scoped to what the requesting user can actually access, and the file listing is filtered by record ownership&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  RAG: materialized views as aggregate views
&lt;/h2&gt;

&lt;p&gt;The aggregate‑view feature from 3.1 (attach a PostgreSQL view to a table so the AI assistant can answer exact “total/how many” questions) now also accepts &lt;strong&gt;materialized views&lt;/strong&gt;, flagged as such in the admin UI — useful when the aggregate query is expensive enough that you’d rather refresh it on a schedule than recompute it on every chat message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9mxmt4p6urpj4j6t39kb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9mxmt4p6urpj4j6t39kb.gif" alt="RAG module" width="560" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Views sync also discovers materialized views alongside regular ones.&lt;/p&gt;




&lt;h2&gt;
  
  
  A unified “Business” look
&lt;/h2&gt;

&lt;p&gt;The admin panel, setup wizard, and frontend were unified onto a single &lt;strong&gt;Business 4+1 color palette&lt;/strong&gt; and one &lt;strong&gt;system‑ui font stack&lt;/strong&gt;, replacing a mix of ad-hoc colors and font declarations across dozens of JS/CSS files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flw0dzjhgw6u90mkhp71x.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flw0dzjhgw6u90mkhp71x.gif" alt="Admin view" width="720" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every front‑end button now shares one height, weight, border radius, and font size instead of drifting per page.&lt;/p&gt;




&lt;h2&gt;
  
  
  Also in this release
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CRM demo: richer install description, plus optional demo‑user and audit‑history install toggles
&lt;/li&gt;
&lt;li&gt;Release packaging excludes &lt;code&gt;creator/&lt;/code&gt;, &lt;code&gt;dist-local/&lt;/code&gt;, and &lt;code&gt;storage/tmp/&lt;/code&gt; from image and release archives
&lt;/li&gt;
&lt;li&gt;Admin docs updated to match actual current module behavior across several sections
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;opensparrow.org&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Discussion
&lt;/h2&gt;

&lt;p&gt;I encourage a substantive discussion, and I'll do my best to answer any questions regarding implementation and configuration.&lt;/p&gt;

</description>
      <category>php</category>
      <category>lowcode</category>
      <category>postgres</category>
      <category>rag</category>
    </item>
    <item>
      <title>OpenSparrow v3.1 - RAG assistant, Record Image Galleries, and Workflow Stored Procedures</title>
      <dc:creator>Tomasz</dc:creator>
      <pubDate>Thu, 06 Aug 2026 06:12:57 +0000</pubDate>
      <link>https://dev.to/wrobeltomasz/opensparrow-v31-rag-assistant-record-image-galleries-and-workflow-stored-procedures-4e97</link>
      <guid>https://dev.to/wrobeltomasz/opensparrow-v31-rag-assistant-record-image-galleries-and-workflow-stored-procedures-4e97</guid>
      <description>&lt;p&gt;Automation rules can now &lt;strong&gt;call out to n8n&lt;/strong&gt;, the &lt;strong&gt;&lt;a href="https://github.com/wrobeltomasz/OpenSparrow/tree/main#rag-module-demo-video" rel="noopener noreferrer"&gt;RAG assistant&lt;/a&gt;&lt;/strong&gt; can answer exact aggregate questions &lt;strong&gt;via admin-configured views&lt;/strong&gt;, tables can have their &lt;strong&gt;own image galleries&lt;/strong&gt;, workflow steps can &lt;strong&gt;run a PostgreSQL stored procedure&lt;/strong&gt;, and the grid gets conditional row highlighting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automations: n8n webhooks
&lt;/h2&gt;

&lt;p&gt;The Automations admin is now split into two tabs - Record (the existing field-update/notification/create-record rules) and n8n. The n8n tab lets a rule fire an outgoing webhook to an n8n workflow instead of (or alongside) the built-in actions, with webhook credentials encrypted at rest. Useful for handing off to Slack, email marketing, or any of the hundreds of services n8n already integrates with, without writing custom PHP.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAG assistant: aggregate views
&lt;/h2&gt;

&lt;p&gt;The AI assistant used to be limited to whatever was on the current grid page, so it had to refuse "how many / total" questions about the whole table. In 3.1, an admin can attach a PostgreSQL view (&lt;code&gt;schema.view&lt;/code&gt;) to a table under RAG settings - a pre-vetted, read-only aggregate query. When that table's page is open, the assistant runs the view (capped at a configurable row limit) and gets the exact figures fenced into the prompt as authoritative data, separate from page content and record text. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwlondabdrl4uk034yqmc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwlondabdrl4uk034yqmc.jpg" alt="The Aggregate Views interface showing how a custom SQL view is attached to a database table to handle aggregated queries to RAG." width="798" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model still never writes or chooses the query itself - it only ever sees the output of a view an admin explicitly configured, with an extra guard that skips owner-restricted tables since a plain view has no per-user filter. The result: questions like "what's the total invoice value this quarter" get an exact answer instead of "I can only see this page."&lt;/p&gt;

&lt;h2&gt;
  
  
  Record image galleries
&lt;/h2&gt;

&lt;p&gt;New per-table image galleries - configure an image column and records show a thumbnail strip in the grid plus an upload gallery on the edit form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftnlv5nf6t38o09impetd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftnlv5nf6t38o09impetd.jpg" alt="A list of records with dedicated icons or image on the right side acting as quick shortcuts to linked documents and files." width="800" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Comes with full Cypress E2E coverage and demo data (contact photos in the CRM demo).&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow steps: PostgreSQL procedure hook
&lt;/h2&gt;

&lt;p&gt;Workflow steps can now call a PostgreSQL stored procedure as part of a guided flow, in addition to the existing table-form steps. The CRM demo ships a worked example. Combined with the record-image upload option added to workflow steps, workflows can now do a lot more than collect form fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grid: conditional row highlighting
&lt;/h2&gt;

&lt;p&gt;Schema-configured row highlight rules color entire grid rows based on column conditions - e.g. flag overdue invoices or high-value deals at a glance - seeded with an invoice example in the CRM demo. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi3qvualge0rxqbsjdzyv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi3qvualge0rxqbsjdzyv.jpg" alt="A sales deals table displaying rows highlighted in different colors corresponding to their 'Stage' status." width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Grid hover/crosshair styling was also reworked: a vertical column highlight alongside the existing row highlight, solid accent header fills, and a fix for the FK cell tooltip getting stuck over open dropdowns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also in this release
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Notes reminders now take a date &lt;strong&gt;and time&lt;/strong&gt;, not just a date&lt;/li&gt;
&lt;li&gt;Optional CRM demo install directly from the first-run setup wizard&lt;/li&gt;
&lt;li&gt;RAG: grid context now built from the actual data model and fenced in the prompt, with a hardened no-answer/partial-answer prompt&lt;/li&gt;
&lt;li&gt;Security: all admin write actions are now guarded by &lt;code&gt;require_not_demo()&lt;/code&gt;, closing a demo-mode bypass in five admin actions; additional CSRF/demo-mode gaps fixed&lt;/li&gt;
&lt;li&gt;License compliance pass: SPDX headers, NOTICE file, canonical FSF license texts, and initials-on-color avatars replacing bundled stock photos&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spw_*&lt;/code&gt; system tables now carry &lt;code&gt;COMMENT ON&lt;/code&gt; descriptions for easier DB introspection&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Following this series?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/wrobeltomasz/opensparrow-v30-gdpr-anonymization-etl-postgresql-native-config-and-a-unified-ui-30mj"&gt;OpenSparrow v3.0 - GDPR Anonymization Goes Production, User Records/Comments, and Ollama Cloud&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opensparrow.org" rel="noopener noreferrer"&gt;opensparrow.org&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/wrobeltomasz/OpenSparrow" rel="noopener noreferrer"&gt;github.com/wrobeltomasz/OpenSparrow&lt;/a&gt;&lt;br&gt;
&lt;a href="https://demo.opensparrow.org" rel="noopener noreferrer"&gt;demo.opensparrow.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>lowcode</category>
      <category>rag</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
