<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Backend on Palmyra</title>
    <link>https://palmyra.dev/docs/tutorial/backend/</link>
    <description>Recent content in Backend on Palmyra</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <atom:link href="https://palmyra.dev/docs/tutorial/backend/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>1. Project setup</title>
      <link>https://palmyra.dev/docs/tutorial/backend/01-setup/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://palmyra.dev/docs/tutorial/backend/01-setup/</guid>
      <description>&lt;h1 id=&#34;1-project-setup&#34;&gt;1. Project setup&lt;a class=&#34;anchor&#34; href=&#34;#1-project-setup&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://github.com/thinxar/clinic/tree/main/service&#34;&gt;&lt;code&gt;thinxar/clinic&lt;/code&gt;&lt;/a&gt; reference service uses plain Groovy Gradle with dependency versions hoisted into a sibling &lt;code&gt;deps.gradle&lt;/code&gt;. This keeps version bumps to one file and avoids drift between the Palmyra core artifact and its extensions.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;a class=&#34;anchor&#34; href=&#34;#prerequisites&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Java 21+&lt;/li&gt;&#xA;&lt;li&gt;Gradle 8.x&lt;/li&gt;&#xA;&lt;li&gt;MariaDB / MySQL / PostgreSQL / Oracle / DB2&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;layout&#34;&gt;Layout&lt;a class=&#34;anchor&#34; href=&#34;#layout&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;service/&#xA;  build.gradle&#xA;  deps.gradle        ← versions + dependency bundles&#xA;  settings.gradle&#xA;  src/main/java/...  com.your.app.AppMain, controller/, entity/, model/, pojo/, handler/, ...&#xA;  src/main/resources/application.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;depsgradle&#34;&gt;&lt;code&gt;deps.gradle&lt;/code&gt;&lt;a class=&#34;anchor&#34; href=&#34;#depsgradle&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Centralise versions and pre-compose reusable dependency bundles:&lt;/p&gt;</description>
    </item>
    <item>
      <title>2. Entities, models, POJOs</title>
      <link>https://palmyra.dev/docs/tutorial/backend/02-schema/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://palmyra.dev/docs/tutorial/backend/02-schema/</guid>
      <description>&lt;h1 id=&#34;2-entities-models-pojos&#34;&gt;2. Entities, models, POJOs&lt;a class=&#34;anchor&#34; href=&#34;#2-entities-models-pojos&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;The clinic sample uses a &lt;strong&gt;three-file separation&lt;/strong&gt; — and the split is load-bearing:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Kind&lt;/th&gt;&#xA;          &lt;th&gt;Package&lt;/th&gt;&#xA;          &lt;th&gt;Role&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;JPA entity&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;entity/&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Persistence shape — JPA annotations, relationships, audit fields&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Palmyra model&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;model/&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Public API shape — &lt;code&gt;@PalmyraType&lt;/code&gt; + &lt;code&gt;@PalmyraField&lt;/code&gt;, what clients see&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Plain POJO&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;pojo/&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Value objects for custom JPQL / native queries — no annotations&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Keeping the Palmyra model separate from the JPA entity lets you flatten joined attributes, hide internal columns, and evolve the API contract without reshaping the database.&lt;/p&gt;</description>
    </item>
    <item>
      <title>3. Publish handlers</title>
      <link>https://palmyra.dev/docs/tutorial/backend/03-handlers/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://palmyra.dev/docs/tutorial/backend/03-handlers/</guid>
      <description>&lt;h1 id=&#34;3-publish-handlers&#34;&gt;3. Publish handlers&lt;a class=&#34;anchor&#34; href=&#34;#3-publish-handlers&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;The clinic sample &lt;strong&gt;does not use the composite &lt;code&gt;CrudHandler&lt;/code&gt;&lt;/strong&gt; — every handler explicitly composes the granular interfaces it needs. The common pattern is &lt;code&gt;QueryHandler + ReadHandler + SaveHandler&lt;/code&gt;, extending a project-local &lt;code&gt;AbstractHandler&lt;/code&gt; that owns the shared concerns.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-abstracthandler-base&#34;&gt;The &lt;code&gt;AbstractHandler&lt;/code&gt; base&lt;a class=&#34;anchor&#34; href=&#34;#the-abstracthandler-base&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;A local base class keeps ACL, audit, and shared dependencies out of every handler:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// handler/AbstractHandler.java&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:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AbstractHandler&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; PreProcessor {&#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:#a6e22e&#34;&gt;@Autowired&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:#66d9ef&#34;&gt;protected&lt;/span&gt; AuthProvider authProvider;&#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:#a6e22e&#34;&gt;@Override&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:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;aclCheck&lt;/span&gt;(Tuple tuple, HandlerContext ctx) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Fine-grained ACL is enforced by palmyra-dbacl-mgmt at the filter&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:#75715e&#34;&gt;// level; handlers get full rights once authentication has passed.&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:#66d9ef&#34;&gt;return&lt;/span&gt; AclRights.&lt;span style=&#34;color:#a6e22e&#34;&gt;ALL&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;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;currentUser&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:#66d9ef&#34;&gt;return&lt;/span&gt; authProvider.&lt;span style=&#34;color:#a6e22e&#34;&gt;getUser&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;minimal-handler--master-data&#34;&gt;Minimal handler — master data&lt;a class=&#34;anchor&#34; href=&#34;#minimal-handler--master-data&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The simplest handler is just a composition declaration:&lt;/p&gt;</description>
    </item>
    <item>
      <title>4. ACL and extensions</title>
      <link>https://palmyra.dev/docs/tutorial/backend/04-export-and-acl/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://palmyra.dev/docs/tutorial/backend/04-export-and-acl/</guid>
      <description>&lt;h1 id=&#34;4-acl-and-extensions&#34;&gt;4. ACL and extensions&lt;a class=&#34;anchor&#34; href=&#34;#4-acl-and-extensions&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;The clinic sample deliberately &lt;strong&gt;does not use &lt;code&gt;@Permission&lt;/code&gt;&lt;/strong&gt; — authorization is split between Spring Security (who is authenticated) and the &lt;code&gt;palmyra-dbacl-mgmt&lt;/code&gt; extension (what each user is allowed to see and change). Password lifecycle is delegated to &lt;code&gt;palmyra-dbpwd-mgmt&lt;/code&gt;. Exports are handled client-side, not by server handlers.&lt;/p&gt;&#xA;&lt;h2 id=&#34;wire-spring-security&#34;&gt;Wire Spring Security&lt;a class=&#34;anchor&#34; href=&#34;#wire-spring-security&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Permit the auth endpoints, authenticate everything else, and return &lt;code&gt;401&lt;/code&gt; on auth failure so the frontend&amp;rsquo;s axios interceptor can redirect to login.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
