<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://blog.treasureboat.org/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.treasureboat.org/" rel="alternate" type="text/html" /><updated>2026-08-19T09:59:56+09:00</updated><id>https://blog.treasureboat.org/feed.xml</id><title type="html">TreasureBoat.org</title><subtitle>TreasureBoat is a Java web application framework in the WebObjects tradition — Enterprise Objects, Key-Value Coding and rule-based UI, with modern Maven and IntelliJ tooling. Guides, notes and release news from the project.</subtitle><entry xml:lang="ja"><title type="html">API エディター</title><link href="https://blog.treasureboat.org/intellij/2026/08/19/ij-api-editor-ja.html" rel="alternate" type="text/html" title="API エディター" /><published>2026-08-19T00:00:00+09:00</published><updated>2026-08-19T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/19/ij-api-editor-ja</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/19/ij-api-editor-ja.html"><![CDATA[<h1 id="api-エディター">API エディター</h1>

<p><a href="/intellij/2026/08/15/ij-project-layout-ja.html">プロジェクト構成</a> の記事で、コンポーネントが
<code class="language-plaintext highlighter-rouge">.html</code>・<code class="language-plaintext highlighter-rouge">.wod</code>・任意の <code class="language-plaintext highlighter-rouge">.api</code>・任意の <code class="language-plaintext highlighter-rouge">.md</code> を持つ <code class="language-plaintext highlighter-rouge">.wo</code> フォルダであることを見ました。この記事では
その <strong><code class="language-plaintext highlighter-rouge">.api</code></strong> ファイルを取り上げます。<code class="language-plaintext highlighter-rouge">.api</code> はコンポーネントの一部なので、これは Component Editor
の予習にもなります。</p>

<p><code class="language-plaintext highlighter-rouge">.api</code> ファイルは、コンポーネントの <strong>公開バインディング</strong>（そのインターフェース）を宣言します。つまり
<em>「これが受け付けるバインディングで、これは必須、これは真偽値を期待する」</em> ということを表します。必ずしも
必要ではありませんが、あると各種ツールがそれを活用します。WOD エディターはコンポーネントのバインディングに
対して <strong>オートコンプリートとバリデーション</strong> を提供し、Component Editor はそのコンポーネントが何を期待して
いるかを把握できます。</p>

<h2 id="api-ファイルの中身"><code class="language-plaintext highlighter-rouge">.api</code> ファイルの中身</h2>

<p>小さな XML ファイルです。API エディターを使えばフォームとして編集できるので、XML を手で触る必要はありません。
実際に書き出されるのは次のような内容です。</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="nt">&lt;tbdefinitions&gt;</span>
    <span class="nt">&lt;tb</span> <span class="na">class=</span><span class="s">"MyComponent.java"</span> <span class="na">tbcomponentcontent=</span><span class="s">"false"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;binding</span> <span class="na">name=</span><span class="s">"editingContext"</span><span class="nt">/&gt;</span>
        <span class="nt">&lt;binding</span> <span class="na">defaults=</span><span class="s">"Boolean"</span> <span class="na">name=</span><span class="s">"allowHiding"</span><span class="nt">/&gt;</span>
        <span class="nt">&lt;validation</span> <span class="na">message=</span><span class="s">"'editingContext' is a required binding."</span><span class="nt">&gt;</span>
            <span class="nt">&lt;unbound</span> <span class="na">name=</span><span class="s">"editingContext"</span><span class="nt">/&gt;</span>
        <span class="nt">&lt;/validation&gt;</span>
    <span class="nt">&lt;/tb&gt;</span>
<span class="nt">&lt;/tbdefinitions&gt;</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">&lt;tb class="…"&gt;</code> – この API が属するコンポーネント</li>
  <li><code class="language-plaintext highlighter-rouge">tbcomponentcontent</code> – コンポーネントが他のコンテンツを <strong>ラップ</strong> できるかどうか（HTML のコンテナのように）</li>
  <li><code class="language-plaintext highlighter-rouge">&lt;binding name="…"&gt;</code> – 公開バインディングごとに 1 つ。<code class="language-plaintext highlighter-rouge">defaults="…"</code> はその <em>Value Set</em> を記録します</li>
  <li><code class="language-plaintext highlighter-rouge">&lt;validation&gt;</code> / <code class="language-plaintext highlighter-rouge">&lt;unbound&gt;</code> – <strong>必須</strong> バインディングの表し方</li>
</ul>

<hr />

<h2 id="エディターの構成">エディターの構成</h2>

<h3 id="component-content">Component Content</h3>

<p>上部のチェックボックスで <strong><code class="language-plaintext highlighter-rouge">tbcomponentcontent</code></strong> を設定します。コンポーネントが親から渡されたコンテンツを
ラップする場合にオンにします。</p>

<h3 id="バインディング一覧">バインディング一覧</h3>

<p>コンポーネントの公開バインディングの一覧です。<strong>必須</strong> のバインディングは <strong>太字</strong> で表示されます。
<strong>Add</strong> / <strong>Remove</strong> で追加・削除します。</p>

<h3 id="バインディングの詳細">バインディングの詳細</h3>

<p>バインディングを選択すると、右側のパネルに次の項目が表示されます。</p>

<table>
  <thead>
    <tr>
      <th>項目</th>
      <th>説明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Name</strong></td>
      <td>バインディング名 — 値を渡すために <code class="language-plaintext highlighter-rouge">.wod</code> で使うのと同じ名前です</td>
    </tr>
    <tr>
      <td><strong>Value Set</strong></td>
      <td>バインディングが期待する値の種類（<code class="language-plaintext highlighter-rouge">.wod</code> でのオートコンプリートに使われます）</td>
    </tr>
    <tr>
      <td><strong>Required</strong></td>
      <td>親が必ず指定しなければならないかどうか（<code class="language-plaintext highlighter-rouge">&lt;validation&gt;</code>／<code class="language-plaintext highlighter-rouge">&lt;unbound&gt;</code> ブロックを書き出します）</td>
    </tr>
    <tr>
      <td><strong>Will Set</strong></td>
      <td>コンポーネントが親へ値を <strong>戻す</strong> かどうか（双方向バインディング）</td>
    </tr>
  </tbody>
</table>

<p><img src="/assets/ApiEditor/Layout.png" alt="Layout" /></p>

<hr />

<h2 id="value-set-の選択肢">Value Set の選択肢</h2>

<p><strong>Value Set</strong> は、そのバインディングが何を期待するかをエディターに伝えるもので、<code class="language-plaintext highlighter-rouge">.wod</code> エディターが
オートコンプリートできるようにします。</p>

<table>
  <thead>
    <tr>
      <th>Value Set</th>
      <th>期待する値</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Undefined</strong></td>
      <td>何でも</td>
    </tr>
    <tr>
      <td><strong>Boolean Set</strong></td>
      <td><code class="language-plaintext highlighter-rouge">true</code> / <code class="language-plaintext highlighter-rouge">false</code></td>
    </tr>
    <tr>
      <td><strong>Actions</strong></td>
      <td>ページやアクション結果を返すメソッド</td>
    </tr>
    <tr>
      <td><strong>Pages</strong></td>
      <td>TBComponent のページ名</td>
    </tr>
    <tr>
      <td><strong>Frameworks</strong></td>
      <td>フレームワークのバンドル名</td>
    </tr>
    <tr>
      <td><strong>Date Format Strings</strong></td>
      <td>日付フォーマットのパターン</td>
    </tr>
    <tr>
      <td><strong>Number Format Strings</strong></td>
      <td>数値フォーマットのパターン</td>
    </tr>
    <tr>
      <td><strong>MIME Types</strong></td>
      <td>MIME タイプの値</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="知っておくと便利なこと">知っておくと便利なこと</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">.api</code> は <strong>任意</strong> です — なくてもコンポーネントは動作します。宣言された、オートコンプリートと
バリデーションの効くインターフェースをコンポーネントに与えるために追加します。他のコンポーネントから
再利用されるものには付けることをおすすめします。</li>
  <li><strong>Required</strong> はバインディングの属性ではなく、<code class="language-plaintext highlighter-rouge">&lt;unbound&gt;</code> エントリを含む独立した <code class="language-plaintext highlighter-rouge">&lt;validation&gt;</code> ブロック
です。これが一覧でバインディングを太字にし、指定が漏れているときに <code class="language-plaintext highlighter-rouge">.wod</code> で警告する仕組みです。</li>
  <li>バインディング名はコンポーネントの Java アクセサメソッドと揃えましょう — <code class="language-plaintext highlighter-rouge">.html</code>・<code class="language-plaintext highlighter-rouge">.wod</code>・<code class="language-plaintext highlighter-rouge">.api</code>・<code class="language-plaintext highlighter-rouge">.java</code>
がすべて同じ名前で会話できるようになります。</li>
</ul>

<hr />

<h2 id="関連記事">関連記事</h2>

<ul>
  <li><strong>Component Editor</strong> — <code class="language-plaintext highlighter-rouge">.api</code> が属する <code class="language-plaintext highlighter-rouge">.wo</code> バンドル <em>(次の記事)</em></li>
  <li><a href="/intellij/2026/08/15/ij-project-layout-ja.html">プロジェクト構成</a> — <code class="language-plaintext highlighter-rouge">.wo</code> の構造</li>
</ul>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><category term="日本語" /><summary type="html"><![CDATA[API エディター]]></summary></entry><entry><title type="html">The API Editor</title><link href="https://blog.treasureboat.org/intellij/2026/08/19/ij-api-editor.html" rel="alternate" type="text/html" title="The API Editor" /><published>2026-08-19T00:00:00+09:00</published><updated>2026-08-19T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/19/ij-api-editor</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/19/ij-api-editor.html"><![CDATA[<h1 id="the-api-editor">The API Editor</h1>

<p>In the <a href="/intellij/2026/08/15/ij-project-layout.html">Project Layout</a> post we saw a
component is a <code class="language-plaintext highlighter-rouge">.wo</code> folder holding <code class="language-plaintext highlighter-rouge">.html</code>, <code class="language-plaintext highlighter-rouge">.wod</code>, an optional <code class="language-plaintext highlighter-rouge">.api</code>, and an
optional <code class="language-plaintext highlighter-rouge">.md</code>. This post is about that <strong><code class="language-plaintext highlighter-rouge">.api</code></strong> file — and it’s really a
warm-up for the Component Editor, because the <code class="language-plaintext highlighter-rouge">.api</code> is part of a component.</p>

<p>An <code class="language-plaintext highlighter-rouge">.api</code> file declares a component’s <strong>public bindings</strong> — its interface. It
says <em>“these are the bindings I accept, this one is required, this one expects a
boolean.”</em> You don’t strictly need it, but when it’s there the tooling uses it:
the WOD editor offers <strong>autocomplete and validation</strong> for the component’s
bindings, and the Component Editor knows what the component expects.</p>

<h2 id="what-a-api-file-looks-like">What a <code class="language-plaintext highlighter-rouge">.api</code> file looks like</h2>

<p>It’s a small XML file. The API Editor lets you edit it as a form so you never
touch the XML by hand, but here is what it writes:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="nt">&lt;tbdefinitions&gt;</span>
    <span class="nt">&lt;tb</span> <span class="na">class=</span><span class="s">"MyComponent.java"</span> <span class="na">tbcomponentcontent=</span><span class="s">"false"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;binding</span> <span class="na">name=</span><span class="s">"editingContext"</span><span class="nt">/&gt;</span>
        <span class="nt">&lt;binding</span> <span class="na">defaults=</span><span class="s">"Boolean"</span> <span class="na">name=</span><span class="s">"allowHiding"</span><span class="nt">/&gt;</span>
        <span class="nt">&lt;validation</span> <span class="na">message=</span><span class="s">"'editingContext' is a required binding."</span><span class="nt">&gt;</span>
            <span class="nt">&lt;unbound</span> <span class="na">name=</span><span class="s">"editingContext"</span><span class="nt">/&gt;</span>
        <span class="nt">&lt;/validation&gt;</span>
    <span class="nt">&lt;/tb&gt;</span>
<span class="nt">&lt;/tbdefinitions&gt;</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">&lt;tb class="…"&gt;</code> – the component this API belongs to</li>
  <li><code class="language-plaintext highlighter-rouge">tbcomponentcontent</code> – whether the component can <strong>wrap</strong> other content (like an HTML container)</li>
  <li><code class="language-plaintext highlighter-rouge">&lt;binding name="…"&gt;</code> – one per public binding; <code class="language-plaintext highlighter-rouge">defaults="…"</code> records its <em>Value Set</em></li>
  <li><code class="language-plaintext highlighter-rouge">&lt;validation&gt;</code> / <code class="language-plaintext highlighter-rouge">&lt;unbound&gt;</code> – how a <strong>required</strong> binding is expressed</li>
</ul>

<hr />

<h2 id="editor-layout">Editor Layout</h2>

<h3 id="component-content">Component Content</h3>

<p>A checkbox at the top sets <strong><code class="language-plaintext highlighter-rouge">tbcomponentcontent</code></strong>. Turn it on when the
component wraps content passed in by its parent.</p>

<h3 id="bindings-list">Bindings List</h3>

<p>The list of the component’s public bindings. <strong>Required</strong> bindings are shown in
<strong>bold</strong>. Use <strong>Add</strong> / <strong>Remove</strong> to manage them.</p>

<h3 id="binding-details">Binding Details</h3>

<p>Select a binding and the right panel shows:</p>

<table>
  <thead>
    <tr>
      <th>Property</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Name</strong></td>
      <td>The binding name — the same name used in the <code class="language-plaintext highlighter-rouge">.wod</code> to pass a value</td>
    </tr>
    <tr>
      <td><strong>Value Set</strong></td>
      <td>What kind of value the binding expects (drives autocomplete in the <code class="language-plaintext highlighter-rouge">.wod</code>)</td>
    </tr>
    <tr>
      <td><strong>Required</strong></td>
      <td>Whether the parent must provide it (writes the <code class="language-plaintext highlighter-rouge">&lt;validation&gt;</code>/<code class="language-plaintext highlighter-rouge">&lt;unbound&gt;</code> block)</td>
    </tr>
    <tr>
      <td><strong>Will Set</strong></td>
      <td>Whether the component pushes a value <strong>back</strong> to the parent (a two-way binding)</td>
    </tr>
  </tbody>
</table>

<p><img src="/assets/ApiEditor/Layout.png" alt="Layout" /></p>

<hr />

<h2 id="value-set-options">Value Set options</h2>

<p>The <strong>Value Set</strong> tells the editor what a binding expects, so the <code class="language-plaintext highlighter-rouge">.wod</code> editor
can autocomplete it:</p>

<table>
  <thead>
    <tr>
      <th>Value Set</th>
      <th>Expects</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Undefined</strong></td>
      <td>anything</td>
    </tr>
    <tr>
      <td><strong>Boolean Set</strong></td>
      <td><code class="language-plaintext highlighter-rouge">true</code> / <code class="language-plaintext highlighter-rouge">false</code></td>
    </tr>
    <tr>
      <td><strong>Actions</strong></td>
      <td>a method returning a page or action result</td>
    </tr>
    <tr>
      <td><strong>Pages</strong></td>
      <td>a TBComponent page name</td>
    </tr>
    <tr>
      <td><strong>Frameworks</strong></td>
      <td>a framework bundle name</td>
    </tr>
    <tr>
      <td><strong>Date Format Strings</strong></td>
      <td>date patterns</td>
    </tr>
    <tr>
      <td><strong>Number Format Strings</strong></td>
      <td>number patterns</td>
    </tr>
    <tr>
      <td><strong>MIME Types</strong></td>
      <td>MIME type values</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="good-to-know">Good to know</h2>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">.api</code> is <strong>optional</strong> — a component works without one. You add it to give
the component a declared, autocompleting, validated interface. Recommended for
anything reused by other components.</li>
  <li><strong>Required</strong> is not an attribute on the binding — it’s a separate
<code class="language-plaintext highlighter-rouge">&lt;validation&gt;</code> block with an <code class="language-plaintext highlighter-rouge">&lt;unbound&gt;</code> entry. That’s what turns the binding
bold in the list and what warns you in the <code class="language-plaintext highlighter-rouge">.wod</code> when it’s missing.</li>
  <li>Match binding names to the component’s Java accessor methods — it keeps the
<code class="language-plaintext highlighter-rouge">.html</code>, <code class="language-plaintext highlighter-rouge">.wod</code>, <code class="language-plaintext highlighter-rouge">.api</code> and <code class="language-plaintext highlighter-rouge">.java</code> all speaking the same names.</li>
</ul>

<hr />

<h2 id="related">Related</h2>

<ul>
  <li><strong>The Component Editor</strong> — the <code class="language-plaintext highlighter-rouge">.wo</code> bundle the <code class="language-plaintext highlighter-rouge">.api</code> belongs to <em>(next post)</em></li>
  <li><a href="/intellij/2026/08/15/ij-project-layout.html">Project Layout</a> — the <code class="language-plaintext highlighter-rouge">.wo</code> anatomy</li>
</ul>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><summary type="html"><![CDATA[The API Editor]]></summary></entry><entry xml:lang="ja"><title type="html">スキーママイグレーション</title><link href="https://blog.treasureboat.org/intellij/2026/08/18/ij-schema-migration-ja.html" rel="alternate" type="text/html" title="スキーママイグレーション" /><published>2026-08-18T00:00:00+09:00</published><updated>2026-08-18T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/18/ij-schema-migration-ja</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/18/ij-schema-migration-ja.html"><![CDATA[<h1 id="スキーママイグレーション">スキーママイグレーション</h1>

<p>これは <strong>もう一方の</strong> マイグレーション — <em>データベースの構造</em> をモデルに合わせて保つためのものです。<a href="/intellij/2026/08/17/ij-eo-migration-editor-ja.html">EO マイグレーション</a>（データ）エディタと混同しやすいので、まずは 1 行で違いを整理します。</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th><strong>スキーママイグレーション</strong> <em>(この記事)</em></th>
      <th>EO マイグレーション</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>作成方法</td>
      <td><a href="/intellij/2026/08/16/ij-entity-editor-ja.html">Entity Editor</a> の <strong>Generate Migration</strong></td>
      <td>Migration Editor</td>
    </tr>
    <tr>
      <td>生成物</td>
      <td><strong><code class="language-plaintext highlighter-rouge">.java</code></strong> クラス</td>
      <td><code class="language-plaintext highlighter-rouge">.xml</code> ファイル</td>
    </tr>
    <tr>
      <td>目的</td>
      <td>テーブル・カラム・外部キー・インデックスを作成 — DB の <strong>形</strong></td>
      <td>起動時にデータを作成／更新／削除</td>
    </tr>
  </tbody>
</table>

<p>エンティティを変更して <a href="/intellij/2026/08/16/ij-entity-editor-ja.html">ハッシュがオレンジ色になったら</a>、スキーママイグレーションでデータベースを追従させます。</p>

<h2 id="generate-migration">Generate Migration</h2>

<p>Entity Editor のツールバーで <strong>Generate Migration</strong> を押すと、次のダイアログが表示されます。</p>

<p><img src="/assets/SchemaMigration/GenerateMigration.png" alt="GenerateMigration" /></p>

<ul>
  <li><strong>Package</strong> – 生成されるクラスの配置先（デフォルトはモデルの <code class="language-plaintext highlighter-rouge">…migrations</code> パッケージ）</li>
  <li><strong>Migration Number</strong> – このマイグレーションの連番（後述の <em>採番</em> を参照）</li>
  <li><strong>Entities to include</strong> – このマイグレーションが対象とするエンティティにチェックを入れます（デフォルトは <em>Select all</em>）</li>
  <li><strong>Preview</strong> – 実際に書き出される Java。オプションを変更するとその場で更新されます</li>
</ul>

<h3 id="オプション">オプション</h3>

<ul>
  <li><strong>Model Dependencies</strong> – このマイグレーションが他のモデルのマイグレーションに依存することを宣言し、モデルをまたいだ順序を正しく保ちます</li>
  <li><strong>New Automatic</strong> – すべてのカラムを書き下す代わりに、現在のモデルバージョンからスキーマを導出する <em>自動</em> マイグレーションを生成します</li>
  <li><strong>Transformation</strong> – 変換フックを含めます（構造変更に伴ってデータを整形するため）</li>
  <li><strong>Run Migration</strong> – SQL データを読み込むエリア（各データベースのコールバック有り）</li>
</ul>

<hr />

<h2 id="生成される内容">生成される内容</h2>

<p>スキーママイグレーションは実際の <strong>Java クラス</strong> です。名前はモデルのプレフィックス + マイグレーション番号（例：<code class="language-plaintext highlighter-rouge">TBTag0</code>）で、<code class="language-plaintext highlighter-rouge">TBEnterpriseMigrationDatabase.Migration</code> を継承します。1 つのマイグレーションクラスが、チェックしたすべてのエンティティをカバーします。処理は <strong>3 つのパス</strong> に分かれています。</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">TBTag0</span> <span class="kd">extends</span> <span class="nc">TBEnterpriseMigrationDatabase</span><span class="o">.</span><span class="na">Migration</span> <span class="o">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">upgrade</span><span class="o">(</span><span class="nc">TBEnterpriseEditingContext</span> <span class="n">ec</span><span class="o">,</span> <span class="nc">TBEnterpriseMigrationDatabase</span> <span class="n">database</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">var</span> <span class="n">table</span> <span class="o">=</span> <span class="n">database</span><span class="o">.</span><span class="na">newTableByEntity</span><span class="o">(</span><span class="nc">TBTagStore</span><span class="o">.</span><span class="na">clazz</span><span class="o">.</span><span class="na">entity</span><span class="o">());</span>
        <span class="n">table</span><span class="o">.</span><span class="na">newStringColumn</span><span class="o">(</span><span class="s">"name_en"</span><span class="o">,</span> <span class="mi">255</span><span class="o">,</span> <span class="no">NOT_NULL</span><span class="o">);</span>
        <span class="n">table</span><span class="o">.</span><span class="na">newBooleanColumn</span><span class="o">(</span><span class="s">"locked"</span><span class="o">,</span> <span class="no">NOT_NULL</span><span class="o">);</span>
        <span class="c1">// … one table per entity, each with its columns</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">foreignKeyUpgrade</span><span class="o">(</span><span class="nc">TBEnterpriseEditingContext</span> <span class="n">ec</span><span class="o">,</span> <span class="nc">TBEnterpriseMigrationDatabase</span> <span class="n">database</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">var</span> <span class="n">table</span> <span class="o">=</span> <span class="n">database</span><span class="o">.</span><span class="na">existingTableByEntity</span><span class="o">(</span><span class="nc">TBTagConnection</span><span class="o">.</span><span class="na">clazz</span><span class="o">.</span><span class="na">entity</span><span class="o">());</span>
        <span class="n">table</span><span class="o">.</span><span class="na">addForeignKey</span><span class="o">(</span><span class="s">"idTag"</span><span class="o">,</span> <span class="nc">TBTagStore</span><span class="o">.</span><span class="na">clazz</span><span class="o">.</span><span class="na">entity</span><span class="o">(),</span> <span class="s">"id"</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">indexUpgrade</span><span class="o">(</span><span class="nc">TBEnterpriseEditingContext</span> <span class="n">ec</span><span class="o">,</span> <span class="nc">TBEnterpriseMigrationDatabase</span> <span class="n">database</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">safeAddIndex</span><span class="o">(</span><span class="n">database</span><span class="o">,</span> <span class="nc">TBTagStore</span><span class="o">.</span><span class="na">clazz</span><span class="o">.</span><span class="na">entity</span><span class="o">(),</span> <span class="n">_TBTagStore</span><span class="o">.</span><span class="na">NAME_EN_KEY</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">upgrade</code></strong> – テーブルとそのカラムを作成します（<code class="language-plaintext highlighter-rouge">newStringColumn</code>・<code class="language-plaintext highlighter-rouge">newIntegerColumn</code>・<code class="language-plaintext highlighter-rouge">newBooleanColumn</code> … に <code class="language-plaintext highlighter-rouge">NOT_NULL</code> / <code class="language-plaintext highlighter-rouge">ALLOWS_NULL</code> を指定）</li>
  <li><strong><code class="language-plaintext highlighter-rouge">foreignKeyUpgrade</code></strong> – 外部キーを追加します</li>
  <li><strong><code class="language-plaintext highlighter-rouge">indexUpgrade</code></strong> – インデックスを追加します（およびデータベース固有のチューニング）</li>
</ul>

<blockquote>
  <p><strong>なぜ 3 パスなのか？</strong> 外部キーは、すべてのテーブルが存在した <strong>後</strong> に追加されます — まだ作成されていないテーブルを外部キーで参照することはできないからです。そこで、まずすべてのテーブルとカラムを作成し（<code class="language-plaintext highlighter-rouge">upgrade</code>）、次にそれらを結ぶキーを追加し（<code class="language-plaintext highlighter-rouge">foreignKeyUpgrade</code>）、最後にインデックスを追加します。</p>
</blockquote>

<hr />

<h2 id="採番">採番</h2>

<p>EO マイグレーションと同様に、<strong>番号は恒久的で順序を持つ履歴</strong> です。<code class="language-plaintext highlighter-rouge">TBTag0</code> はマイグレーション <code class="language-plaintext highlighter-rouge">0</code> で、そのモデルへの次の構造変更は <strong>新しい</strong> クラス <code class="language-plaintext highlighter-rouge">TBTag1</code>、その次は <code class="language-plaintext highlighter-rouge">TBTag2</code>、というように続きます。すでにどこかで実行済みのマイグレーションは決して編集せず、次の番号を追加します。フレームワークは各データベースがどの番号まで進んでいるかを記録し、まだ適用していないものだけを実行します。</p>

<p>EO マイグレーション（Migration Editor で編集する <code class="language-plaintext highlighter-rouge">.xml</code> ファイル）とは異なり、スキーママイグレーションは <strong>素の Java</strong> です。生成後は通常の Java エディタで開いて手動で調整できます。</p>

<hr />

<h2 id="関連記事">関連記事</h2>

<ul>
  <li><a href="/intellij/2026/08/16/ij-entity-editor-ja.html">Entity Editor</a> — <strong>Generate Migration</strong> がある場所</li>
  <li><a href="/intellij/2026/08/17/ij-eo-migration-editor-ja.html">EO Migration Editor</a> — <em>データ</em> のマイグレーション、もう一方の種類</li>
  <li><a href="/intellij/2026/08/15/ij-project-layout-ja.html">プロジェクト構成</a></li>
</ul>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><category term="日本語" /><summary type="html"><![CDATA[スキーママイグレーション]]></summary></entry><entry><title type="html">Schema Migrations</title><link href="https://blog.treasureboat.org/intellij/2026/08/18/ij-schema-migration.html" rel="alternate" type="text/html" title="Schema Migrations" /><published>2026-08-18T00:00:00+09:00</published><updated>2026-08-18T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/18/ij-schema-migration</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/18/ij-schema-migration.html"><![CDATA[<h1 id="schema-migrations">Schema Migrations</h1>

<p>This is the <strong>other</strong> migration — the one that keeps the <em>database structure</em> in
step with your model. It is easy to confuse with the <a href="/intellij/2026/08/17/ij-eo-migration-editor.html">EO Migration</a>
(data) editor, so the one-line difference first:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th><strong>Schema Migration</strong> <em>(this post)</em></th>
      <th>EO Migration</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Made with</td>
      <td><strong>Generate Migration</strong> in the <a href="/intellij/2026/08/16/ij-entity-editor.html">Entity Editor</a></td>
      <td>the Migration Editor</td>
    </tr>
    <tr>
      <td>Produces</td>
      <td>a <strong><code class="language-plaintext highlighter-rouge">.java</code></strong> class</td>
      <td>an <code class="language-plaintext highlighter-rouge">.xml</code> file</td>
    </tr>
    <tr>
      <td>Purpose</td>
      <td>create tables, columns, foreign keys, indexes — the DB <strong>shape</strong></td>
      <td>create / update / delete <strong>data</strong> at boot</td>
    </tr>
  </tbody>
</table>

<p>When you change an entity and its <a href="/intellij/2026/08/16/ij-entity-editor.html">hash turns orange</a>,
a schema migration is how you bring the database along.</p>

<h2 id="generate-migration">Generate Migration</h2>

<p>Press <strong>Generate Migration</strong> in the Entity Editor toolbar and you get this dialog:</p>

<p><img src="/assets/SchemaMigration/GenerateMigration.png" alt="GenerateMigration" /></p>

<ul>
  <li><strong>Package</strong> – where the generated class goes (defaults to your model’s <code class="language-plaintext highlighter-rouge">…migrations</code> package)</li>
  <li><strong>Migration Number</strong> – the sequence number for this migration (see <em>Numbering</em> below)</li>
  <li><strong>Entities to include</strong> – tick the entities this migration should cover (<em>Select all</em> by default)</li>
  <li><strong>Preview</strong> – the exact Java that will be written, updated live as you change the options</li>
</ul>

<h3 id="options">Options</h3>

<ul>
  <li><strong>Model Dependencies</strong> – declare that this migration depends on other models’ migrations, so cross-model order is correct</li>
  <li><strong>New Automatic</strong> – generate an <em>automatic</em> migration that derives the schema from the current model version, instead of spelling out every column</li>
  <li><strong>Transformation</strong> – include a transformation hook (for reshaping data as part of the structural change)</li>
  <li><strong>Run Migration</strong> – apply data sql loading to the migration that should run for data import</li>
</ul>

<hr />

<h2 id="what-gets-generated">What gets generated</h2>

<p>A schema migration is a real <strong>Java class</strong> — the model’s prefix and the migration
number (e.g. <code class="language-plaintext highlighter-rouge">TBTag0</code>) — that extends <code class="language-plaintext highlighter-rouge">TBEnterpriseMigrationDatabase.Migration</code>.
One migration class covers all the entities you ticked. It does its work in
<strong>three passes</strong>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">TBTag0</span> <span class="kd">extends</span> <span class="nc">TBEnterpriseMigrationDatabase</span><span class="o">.</span><span class="na">Migration</span> <span class="o">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">upgrade</span><span class="o">(</span><span class="nc">TBEnterpriseEditingContext</span> <span class="n">ec</span><span class="o">,</span> <span class="nc">TBEnterpriseMigrationDatabase</span> <span class="n">database</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">var</span> <span class="n">table</span> <span class="o">=</span> <span class="n">database</span><span class="o">.</span><span class="na">newTableByEntity</span><span class="o">(</span><span class="nc">TBTagStore</span><span class="o">.</span><span class="na">clazz</span><span class="o">.</span><span class="na">entity</span><span class="o">());</span>
        <span class="n">table</span><span class="o">.</span><span class="na">newStringColumn</span><span class="o">(</span><span class="s">"name_en"</span><span class="o">,</span> <span class="mi">255</span><span class="o">,</span> <span class="no">NOT_NULL</span><span class="o">);</span>
        <span class="n">table</span><span class="o">.</span><span class="na">newBooleanColumn</span><span class="o">(</span><span class="s">"locked"</span><span class="o">,</span> <span class="no">NOT_NULL</span><span class="o">);</span>
        <span class="c1">// … one table per entity, each with its columns</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">foreignKeyUpgrade</span><span class="o">(</span><span class="nc">TBEnterpriseEditingContext</span> <span class="n">ec</span><span class="o">,</span> <span class="nc">TBEnterpriseMigrationDatabase</span> <span class="n">database</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">var</span> <span class="n">table</span> <span class="o">=</span> <span class="n">database</span><span class="o">.</span><span class="na">existingTableByEntity</span><span class="o">(</span><span class="nc">TBTagConnection</span><span class="o">.</span><span class="na">clazz</span><span class="o">.</span><span class="na">entity</span><span class="o">());</span>
        <span class="n">table</span><span class="o">.</span><span class="na">addForeignKey</span><span class="o">(</span><span class="s">"idTag"</span><span class="o">,</span> <span class="nc">TBTagStore</span><span class="o">.</span><span class="na">clazz</span><span class="o">.</span><span class="na">entity</span><span class="o">(),</span> <span class="s">"id"</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">indexUpgrade</span><span class="o">(</span><span class="nc">TBEnterpriseEditingContext</span> <span class="n">ec</span><span class="o">,</span> <span class="nc">TBEnterpriseMigrationDatabase</span> <span class="n">database</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">safeAddIndex</span><span class="o">(</span><span class="n">database</span><span class="o">,</span> <span class="nc">TBTagStore</span><span class="o">.</span><span class="na">clazz</span><span class="o">.</span><span class="na">entity</span><span class="o">(),</span> <span class="n">_TBTagStore</span><span class="o">.</span><span class="na">NAME_EN_KEY</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">upgrade</code></strong> – creates the tables and their columns (<code class="language-plaintext highlighter-rouge">newStringColumn</code>, <code class="language-plaintext highlighter-rouge">newIntegerColumn</code>, <code class="language-plaintext highlighter-rouge">newBooleanColumn</code>, … with <code class="language-plaintext highlighter-rouge">NOT_NULL</code> / <code class="language-plaintext highlighter-rouge">ALLOWS_NULL</code>)</li>
  <li><strong><code class="language-plaintext highlighter-rouge">foreignKeyUpgrade</code></strong> – adds the foreign keys</li>
  <li><strong><code class="language-plaintext highlighter-rouge">indexUpgrade</code></strong> – adds the indexes (and any database-specific tuning)</li>
</ul>

<blockquote>
  <p><strong>Why three passes?</strong> Foreign keys are added <strong>after</strong> every table exists — you
can’t point a foreign key at a table that hasn’t been created yet. So all tables
and columns go in first (<code class="language-plaintext highlighter-rouge">upgrade</code>), then the keys that link them
(<code class="language-plaintext highlighter-rouge">foreignKeyUpgrade</code>), then the indexes.</p>
</blockquote>

<hr />

<h2 id="numbering">Numbering</h2>

<p>Like EO migrations, the <strong>number is a permanent, ordered history</strong>. <code class="language-plaintext highlighter-rouge">TBTag0</code> is
migration <code class="language-plaintext highlighter-rouge">0</code>; the next structural change to that model is a <strong>new</strong> class
<code class="language-plaintext highlighter-rouge">TBTag1</code>, then <code class="language-plaintext highlighter-rouge">TBTag2</code>, and so on. You never edit a migration that has already
run somewhere — you add the next number. The framework tracks which number a
database is on and applies only the ones it hasn’t seen.</p>

<p>Unlike an EO migration (an <code class="language-plaintext highlighter-rouge">.xml</code> file you edit in the Migration Editor), a schema
migration is <strong>plain Java</strong> — once generated you can open and hand-tune it in the
normal Java editor.</p>

<hr />

<h2 id="related">Related</h2>

<ul>
  <li><a href="/intellij/2026/08/16/ij-entity-editor.html">The Entity Editor</a> — where <strong>Generate Migration</strong> lives</li>
  <li><a href="/intellij/2026/08/17/ij-eo-migration-editor.html">The EO Migration Editor</a> — the <em>data</em> migration, the other kind</li>
  <li><a href="/intellij/2026/08/15/ij-project-layout.html">Project Layout</a></li>
</ul>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><summary type="html"><![CDATA[Schema Migrations]]></summary></entry><entry xml:lang="ja"><title type="html">EO マイグレーションエディタ</title><link href="https://blog.treasureboat.org/intellij/2026/08/17/ij-eo-migration-editor-ja.html" rel="alternate" type="text/html" title="EO マイグレーションエディタ" /><published>2026-08-17T00:00:00+09:00</published><updated>2026-08-17T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/17/ij-eo-migration-editor-ja</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/17/ij-eo-migration-editor-ja.html"><![CDATA[<h1 id="eo-マイグレーションエディタ">EO マイグレーションエディタ</h1>

<p>TreasureBoat には名前に「マイグレーション」と付くものが <strong>2 つ</strong> あり、混同しがちです。
まずはこの 2 つを区別しておきましょう。この記事で扱うのは 2 つ目だけです。</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>スキーママイグレーション</th>
      <th><strong>EO マイグレーション</strong> <em>(この記事)</em></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>作成方法</td>
      <td><a href="/intellij/2026/08/16/ij-entity-editor-ja.html">Entity Editor</a> の <strong>Generate Migration</strong> ボタン</td>
      <td><strong>Migration Editor</strong>（<code class="language-plaintext highlighter-rouge">.xml</code> ファイルを開きます）</td>
    </tr>
    <tr>
      <td>生成物</td>
      <td><strong><code class="language-plaintext highlighter-rouge">.java</code></strong> クラス</td>
      <td><strong><code class="language-plaintext highlighter-rouge">.xml</code></strong> ファイル</td>
    </tr>
    <tr>
      <td>目的</td>
      <td><strong>データベースの構造</strong> を同期する — テーブル作成、カラム追加、インデックス、外部キー</td>
      <td>起動時に <strong>データ</strong>（EO インスタンス）を作成・更新・削除する</td>
    </tr>
  </tbody>
</table>

<p>つまり、スキーママイグレーションはデータベースの <em>形</em> を変え、<strong>EO マイグレーションはそこにデータを入れます</strong>（あるいはデータを変更・削除します）。このエディタは後者、すなわち <a href="/intellij/2026/08/15/ij-project-layout-ja.html">Project Layout</a> の記事で見た <code class="language-plaintext highlighter-rouge">EOMigration/</code> や <code class="language-plaintext highlighter-rouge">EOTestMigration/</code> の中にある <code class="language-plaintext highlighter-rouge">.xml</code> ファイルを扱うものです。</p>

<h2 id="eo-マイグレーションとは">EO マイグレーションとは</h2>

<p>EO マイグレーションとは、<strong>アプリケーションの起動時</strong> に実行され、Enterprise Object を作成・更新・削除する小さな <code class="language-plaintext highlighter-rouge">.xml</code> ファイルです。アプリに存在していてほしいシードデータ — CMS ページ、ロール、ポリシー、ナビゲーションバー、スケジュールジョブなど — を用意します。</p>

<ul>
  <li>ファイルは <code class="language-plaintext highlighter-rouge">EOMigration/</code>（全環境）または <code class="language-plaintext highlighter-rouge">EOTestMigration/</code>（開発・テスト専用）に置かれます。</li>
  <li><strong>番号付き</strong>（<code class="language-plaintext highlighter-rouge">1001_…</code>、<code class="language-plaintext highlighter-rouge">0101_…</code>）で、<strong>順番どおり</strong> に実行されます。</li>
  <li>一度リリースしたマイグレーションは <strong>変更不可</strong> です — 古いファイルは決して編集せず、変更は <strong>新しい</strong> 番号のファイルに入れます。（番号は恒久的で順序を持った履歴です。）</li>
</ul>

<p><img src="/assets/EOMigrationEditor/Overview.png" alt="Overview" /></p>

<hr />

<h2 id="file-settings">File Settings</h2>

<p>各ファイルは <strong>1 つの操作ブロック</strong> であり、エディタ上部で設定します。</p>

<ul>
  <li><strong>Root Type</strong> – ファイル全体の操作：<strong>Create</strong>、<strong>Update</strong>、<strong>Delete</strong>、または <strong>SaveChanges</strong></li>
  <li><strong>Target</strong> – 適用する環境。例：<code class="language-plaintext highlighter-rouge">dev,common,deploy</code></li>
  <li><strong>Condition</strong> – <strong>冪等性のためのガード</strong>：条件が真のときだけブロックが実行されます。典型的には <code class="language-plaintext highlighter-rouge">!hasEoForKey('TBPolicy.&lt;uuid&gt;')</code> — <em>「まだ存在しない場合だけ作成する」</em> という意味です。これにより、起動のたびにマイグレーションが実行されてもデータが重複しないようになっています。</li>
  <li><strong>Version</strong> – <em>(任意)</em> マイグレーションが対象とするモデルバージョン</li>
  <li><strong>Face</strong> – <em>(任意)</em> 特定のフェイスに限定します。例：<code class="language-plaintext highlighter-rouge">{FaceId1},{FaceId2}</code></li>
  <li><strong>LockingEO</strong> – <em>(任意)</em> マイグレーション実行中にロックするストアドプロパティ</li>
</ul>

<p><img src="/assets/EOMigrationEditor/FileSettings.png" alt="FileSettings" /></p>

<blockquote>
  <p><strong>知っておくと便利:</strong> <strong>1 ファイルにつき操作ブロックは 1 つ</strong> にしてください。1 つのファイルを
複数のブロックに分けると確実には実行されません — 別の番号のファイルに分けましょう。</p>
</blockquote>

<hr />

<h2 id="eo-リスト左">EO リスト（左）</h2>

<p>設定の下には、操作の対象となる Enterprise Object の一覧が表示されます。各行が 1 つのオブジェクトで、<code class="language-plaintext highlighter-rouge">Entity (identifier)</code> の形式で表示されます。例：<code class="language-plaintext highlighter-rouge">TBPolicy (show.navigation)</code>。リスト上部の小さなツールバーで行の追加・削除・並べ替えができます。</p>

<p><img src="/assets/EOMigrationEditor/Tree.png" alt="Tree" /></p>

<hr />

<h2 id="properties--xml-preview右">Properties / XML Preview（右）</h2>

<p>行を選択すると、右側に 2 つのタブが表示されます。</p>

<ul>
  <li><strong>Properties</strong> – オブジェクトを編集します：
    <ul>
      <li><strong>Entity</strong> – EO のエンティティ種別（例：<code class="language-plaintext highlighter-rouge">TBKVDataStorage</code>）</li>
      <li><strong><code class="language-plaintext highlighter-rouge">_qualifier</code></strong> – このオブジェクトを <strong>識別する</strong> キー。<code class="language-plaintext highlighter-rouge">Create</code> では <code class="language-plaintext highlighter-rouge">Condition</code> のチェックに使われる識別子であり、<code class="language-plaintext highlighter-rouge">Update</code>/<code class="language-plaintext highlighter-rouge">Delete</code> では変更対象の既存オブジェクトを <strong>見つける</strong> ためのキーです。</li>
      <li><strong>Attribute / Value</strong> テーブル – 設定するフィールドの値</li>
    </ul>
  </li>
  <li><strong>XML Preview</strong> – ディスクに書き込まれる実際の XML。保存する前に一度目を通しておくとよいでしょう。</li>
</ul>

<p><img src="/assets/EOMigrationEditor/Properties.png" alt="Properties" /></p>

<hr />

<h2 id="4-つの操作">4 つの操作</h2>

<table>
  <thead>
    <tr>
      <th>Root Type</th>
      <th>内容</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Create</strong></td>
      <td>新しい EO インスタンスを挿入します（<code class="language-plaintext highlighter-rouge">Condition</code> によって重複しないようにガードされます）</td>
    </tr>
    <tr>
      <td><strong>Update</strong></td>
      <td>既存インスタンスを変更します（<code class="language-plaintext highlighter-rouge">_qualifier</code> で検索）</td>
    </tr>
    <tr>
      <td><strong>Delete</strong></td>
      <td>既存インスタンスを削除します（<code class="language-plaintext highlighter-rouge">_qualifier</code> で検索）</td>
    </tr>
    <tr>
      <td><strong>SaveChanges</strong></td>
      <td>蓄積された変更をコミットします</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="関連">関連</h2>

<ul>
  <li><a href="/intellij/2026/08/16/ij-entity-editor-ja.html">Entity Editor</a> — その <strong>Generate Migration</strong> ボタン（もう一方の <em>スキーマ</em> マイグレーション）</li>
  <li><a href="/intellij/2026/08/15/ij-project-layout-ja.html">Project Layout</a> — <code class="language-plaintext highlighter-rouge">EOMigration/</code> と <code class="language-plaintext highlighter-rouge">EOTestMigration/</code> の場所</li>
  <li><strong>スキーママイグレーション</strong> — スキーママイグレーションファイルの編集 <em>(次の記事)</em></li>
</ul>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><category term="日本語" /><summary type="html"><![CDATA[EO マイグレーションエディタ]]></summary></entry><entry><title type="html">The EO Migration Editor</title><link href="https://blog.treasureboat.org/intellij/2026/08/17/ij-eo-migration-editor.html" rel="alternate" type="text/html" title="The EO Migration Editor" /><published>2026-08-17T00:00:00+09:00</published><updated>2026-08-17T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/17/ij-eo-migration-editor</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/17/ij-eo-migration-editor.html"><![CDATA[<h1 id="the-eo-migration-editor">The EO Migration Editor</h1>

<p>TreasureBoat has <strong>two</strong> things with “migration” in the name, and they are easy
to mix up. Let’s separate them first, because this post is only about the second:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>Schema Migration</th>
      <th><strong>EO Migration</strong> <em>(this post)</em></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Made with</td>
      <td>the <strong>Generate Migration</strong> button in the <a href="/intellij/2026/08/16/ij-entity-editor.html">Entity Editor</a></td>
      <td>the <strong>Migration Editor</strong> (opens the <code class="language-plaintext highlighter-rouge">.xml</code> file)</td>
    </tr>
    <tr>
      <td>Produces</td>
      <td>a <strong><code class="language-plaintext highlighter-rouge">.java</code></strong> class</td>
      <td>an <strong><code class="language-plaintext highlighter-rouge">.xml</code></strong> file</td>
    </tr>
    <tr>
      <td>Purpose</td>
      <td>sync the <strong>database structure</strong> — create tables, add columns, indexes, foreign keys</td>
      <td>create / update / delete <strong>data</strong> (EO instances) at boot</td>
    </tr>
  </tbody>
</table>

<p>So: schema migrations change the <em>shape</em> of the database; <strong>EO migrations put
data in it</strong> (or change/remove data). This editor is for the second kind — the
<code class="language-plaintext highlighter-rouge">.xml</code> files under <code class="language-plaintext highlighter-rouge">EOMigration/</code> and <code class="language-plaintext highlighter-rouge">EOTestMigration/</code> you saw in the
<a href="/intellij/2026/08/15/ij-project-layout.html">Project Layout</a> post.</p>

<h2 id="what-an-eo-migration-is">What an EO migration is</h2>

<p>An EO migration is a small <code class="language-plaintext highlighter-rouge">.xml</code> file that runs <strong>at application boot</strong> and
creates, updates or deletes Enterprise Objects — the seed data your app needs to
exist: CMS pages, roles, policies, navigation bars, scheduled jobs, and so on.</p>

<ul>
  <li>Files live in <code class="language-plaintext highlighter-rouge">EOMigration/</code> (all environments) or <code class="language-plaintext highlighter-rouge">EOTestMigration/</code> (dev/test only).</li>
  <li>They are <strong>numbered</strong> (<code class="language-plaintext highlighter-rouge">1001_…</code>, <code class="language-plaintext highlighter-rouge">0101_…</code>) and run <strong>in order</strong>.</li>
  <li>Once a migration has shipped it is <strong>immutable</strong> — you never edit an old file; a new change goes in a <strong>new</strong> numbered file. (The numbers are a permanent, ordered history.)</li>
</ul>

<p><img src="/assets/EOMigrationEditor/Overview.png" alt="Overview" /></p>

<hr />

<h2 id="file-settings">File Settings</h2>

<p>Each file is <strong>one operation block</strong>, configured at the top of the editor:</p>

<ul>
  <li><strong>Root Type</strong> – the operation for the whole file: <strong>Create</strong>, <strong>Update</strong>, <strong>Delete</strong>, or <strong>SaveChanges</strong></li>
  <li><strong>Target</strong> – which environments it applies to, e.g. <code class="language-plaintext highlighter-rouge">dev,common,deploy</code></li>
  <li><strong>Condition</strong> – an <strong>idempotency guard</strong>: the block only runs if the condition is true. Typically <code class="language-plaintext highlighter-rouge">!hasEoForKey('TBPolicy.&lt;uuid&gt;')</code> — <em>“only create this if it isn’t already there.”</em> This is what makes it safe for the migration to run on every boot without duplicating data.</li>
  <li><strong>Version</strong> – <em>(optional)</em> a model version the migration targets</li>
  <li><strong>Face</strong> – <em>(optional)</em> limit the migration to specific faces, e.g. <code class="language-plaintext highlighter-rouge">{FaceId1},{FaceId2}</code></li>
  <li><strong>LockingEO</strong> – <em>(optional)</em> a stored property to lock on while the migration runs</li>
</ul>

<p><img src="/assets/EOMigrationEditor/FileSettings.png" alt="FileSettings" /></p>

<blockquote>
  <p><strong>Good to know:</strong> keep <strong>one operation block per file</strong>. Splitting a file into
several blocks does not execute reliably — make a separate numbered file
instead.</p>
</blockquote>

<hr />

<h2 id="the-eo-list-left">The EO list (left)</h2>

<p>Below the settings is the list of Enterprise Objects the operation acts on — each
row is one object, shown as <code class="language-plaintext highlighter-rouge">Entity (identifier)</code>, for example
<code class="language-plaintext highlighter-rouge">TBPolicy (show.navigation)</code>. The small toolbar above the list adds, removes and
reorders rows.</p>

<p><img src="/assets/EOMigrationEditor/Tree.png" alt="Tree" /></p>

<hr />

<h2 id="properties--xml-preview-right">Properties / XML Preview (right)</h2>

<p>Select a row and the right side gives you two tabs:</p>

<ul>
  <li><strong>Properties</strong> – edit the object:
    <ul>
      <li><strong>Entity</strong> – the EO entity type (e.g. <code class="language-plaintext highlighter-rouge">TBKVDataStorage</code>)</li>
      <li><strong><code class="language-plaintext highlighter-rouge">_qualifier</code></strong> – the key that <strong>identifies</strong> this object. For <code class="language-plaintext highlighter-rouge">Create</code> it’s the identity used by the <code class="language-plaintext highlighter-rouge">Condition</code> check; for <code class="language-plaintext highlighter-rouge">Update</code>/<code class="language-plaintext highlighter-rouge">Delete</code> it’s how the migration <strong>finds</strong> the existing object to change.</li>
      <li><strong>Attribute / Value</strong> table – the field values to set</li>
    </ul>
  </li>
  <li><strong>XML Preview</strong> – the exact XML that will be written to disk. Always worth a glance before saving.</li>
</ul>

<p><img src="/assets/EOMigrationEditor/Properties.png" alt="Properties" /></p>

<hr />

<h2 id="the-four-operations">The four operations</h2>

<table>
  <thead>
    <tr>
      <th>Root Type</th>
      <th>What it does</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Create</strong></td>
      <td>Insert new EO instances (guarded by <code class="language-plaintext highlighter-rouge">Condition</code> so it won’t duplicate)</td>
    </tr>
    <tr>
      <td><strong>Update</strong></td>
      <td>Change existing instances, found by <code class="language-plaintext highlighter-rouge">_qualifier</code></td>
    </tr>
    <tr>
      <td><strong>Delete</strong></td>
      <td>Remove existing instances, found by <code class="language-plaintext highlighter-rouge">_qualifier</code></td>
    </tr>
    <tr>
      <td><strong>SaveChanges</strong></td>
      <td>Commit the accumulated changes</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="related">Related</h2>

<ul>
  <li><a href="/intellij/2026/08/16/ij-entity-editor.html">The Entity Editor</a> — and its <strong>Generate Migration</strong> button (the <em>schema</em> migration, the other kind)</li>
  <li><a href="/intellij/2026/08/15/ij-project-layout.html">Project Layout</a> — where <code class="language-plaintext highlighter-rouge">EOMigration/</code> and <code class="language-plaintext highlighter-rouge">EOTestMigration/</code> live</li>
  <li>The <strong>Schema Migrations</strong> — editing the Schema migration files <em>(next post)</em></li>
</ul>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><summary type="html"><![CDATA[The EO Migration Editor]]></summary></entry><entry xml:lang="ja"><title type="html">エンティティエディタ</title><link href="https://blog.treasureboat.org/intellij/2026/08/16/ij-entity-editor-ja.html" rel="alternate" type="text/html" title="エンティティエディタ" /><published>2026-08-16T00:00:00+09:00</published><updated>2026-08-16T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/16/ij-entity-editor-ja</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/16/ij-entity-editor-ja.html"><![CDATA[<h1 id="エンティティエディタ">エンティティエディタ</h1>

<p><a href="/intellij/2026/08/15/ij-project-layout-ja.html">プロジェクト構成</a> の記事では、<code class="language-plaintext highlighter-rouge">resources</code>
フォルダに <code class="language-plaintext highlighter-rouge">.eomodeld</code>（<strong>EO モデル</strong>）が入っていることを見ました。この記事では、それを
編集するためのエディタを取り上げます。</p>

<p><strong>EOModel</strong> は TreasureBoat のオブジェクト・リレーショナルマッピングです。エンティティ
（テーブル）、その属性（カラム）、そしてそれらの間のリレーションシップ（結合）を、Java
コード内のアノテーションではなく、宣言的にデータとして記述します。<code class="language-plaintext highlighter-rouge">.eomodeld</code> を開くと、
プラグインは生の plist ファイルではなく、ビジュアルな <strong>エンティティエディタ</strong> を提供します。</p>

<h2 id="eomodel-とは">EOModel とは</h2>

<p><code class="language-plaintext highlighter-rouge">.eomodeld</code> は単一のファイルではなく、NeXTSTEP 形式の plist ファイルをまとめた
<strong>バンドル</strong>（フォルダ）です。</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">index.eomodeld</code> – モデルのメタデータ（接続情報、命名規則）</li>
  <li>エンティティごとの <code class="language-plaintext highlighter-rouge">.plist</code> – そのエンティティの属性・リレーションシップ・フェッチ仕様</li>
</ul>

<p>これらの plist を手で編集する必要はありません。そのためのエディタです。</p>

<p><img src="/assets/EntityEditor/Overview.png" alt="Overview" /></p>

<hr />

<h2 id="エディタの構成">エディタの構成</h2>

<p>エディタには 2 つのパネルがあります。左側の <strong>ツリー</strong> と、右側の <strong>プロパティパネル</strong> です。</p>

<h3 id="エンティティツリー左">エンティティツリー（左）</h3>

<p>ツリーにはモデル全体の構造が表示されます。</p>

<ul>
  <li><strong>Model</strong> – <code class="language-plaintext highlighter-rouge">.eomodeld</code> バンドル（ルート）
    <ul>
      <li><strong>Entity</strong> – モデル内の各エンティティ
        <ul>
          <li><strong>Attributes</strong> – カラム</li>
          <li><strong>Relationships</strong> – 他のエンティティへの結合</li>
          <li><strong>Fetch Specifications</strong> – あらかじめ定義された名前付きクエリ</li>
          <li><strong>Indexes</strong> – データベースのインデックス</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<p>ノードを右クリックすると、エンティティ・属性・リレーションシップ・フェッチ仕様・インデックスの
追加や削除、エンティティの <strong>サブクラス</strong> 作成ができます。</p>

<p><img src="/assets/EntityEditor/EntityTreeRightClick.png" alt="EntityTreeRightClick" /></p>

<p>また、必要に応じて次のファイルも作成できます。</p>

<ul>
  <li>Create REST Controller…</li>
  <li>Create Sangria Rules…</li>
  <li>Create Sangria Delegate…</li>
</ul>

<h3 id="プロパティパネル右">プロパティパネル（右）</h3>

<p>任意のノードを選択すると、右側のパネルにそのプロパティが表示され、編集できます — 属性の
カラムや型、リレーションシップの参照先や削除ルールなどです。</p>

<p><img src="/assets/EntityEditor/Layout.png" alt="Layout" /></p>

<hr />

<h2 id="ツールバー">ツールバー</h2>

<table>
  <thead>
    <tr>
      <th>ボタン</th>
      <th>機能</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Save</strong></td>
      <td>すべての変更を <code class="language-plaintext highlighter-rouge">.eomodeld</code> の plist に書き戻します</td>
    </tr>
    <tr>
      <td><strong>Add Attribute</strong></td>
      <td>選択中のエンティティにカラムを追加します</td>
    </tr>
    <tr>
      <td><strong>Add Relationship</strong></td>
      <td>選択中のエンティティから結合を追加します</td>
    </tr>
    <tr>
      <td><strong>Generate Migration</strong></td>
      <td>モデルの変更に対するマイグレーションファイルを作成します（後述）</td>
    </tr>
    <tr>
      <td><strong>Generate EO</strong></td>
      <td>モデルから Java クラスを生成します</td>
    </tr>
    <tr>
      <td><strong>Verify</strong></td>
      <td>保存前にモデルの整合性エラーをチェックします</td>
    </tr>
    <tr>
      <td><strong>Select in Project View</strong></td>
      <td>プロジェクトビューで <code class="language-plaintext highlighter-rouge">.eomodeld</code> フォルダにジャンプします</td>
    </tr>
    <tr>
      <td><strong>Template Path</strong></td>
      <td><em>Generate EO</em> で使う Velocity テンプレートを選択します</td>
    </tr>
    <tr>
      <td><strong>Help</strong></td>
      <td>このエディタの組み込みヘルプを開きます</td>
    </tr>
  </tbody>
</table>

<p><img src="/assets/EntityEditor/Toolbar.png" alt="Toolbar" /></p>

<hr />

<h2 id="押さえておきたいプロパティ">押さえておきたいプロパティ</h2>

<h3 id="エンティティ">エンティティ</h3>

<table>
  <thead>
    <tr>
      <th>プロパティ</th>
      <th>説明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>name</strong></td>
      <td>エンティティ名（Java クラスに対応します）</td>
    </tr>
    <tr>
      <td><strong>tableName</strong></td>
      <td>データベースのテーブル</td>
    </tr>
    <tr>
      <td><strong>className</strong></td>
      <td>完全修飾の Java クラス名</td>
    </tr>
    <tr>
      <td><strong>parentName</strong></td>
      <td>継承のための親エンティティ</td>
    </tr>
    <tr>
      <td><strong>isAbstractEntity</strong></td>
      <td>抽象エンティティ — 自身のテーブルを持ちません</td>
    </tr>
  </tbody>
</table>

<h4 id="ベーシックパネル">ベーシック・パネル</h4>

<p><img src="/assets/EntityEditor/EntBasic.png" alt="Basic" /></p>

<h4 id="アドバンストパネル">アドバンスト・パネル</h4>

<p><img src="/assets/EntityEditor/EntAdvanced.png" alt="Advanced" /></p>

<h4 id="ローカライズパネル">ローカライズ・パネル</h4>

<p><img src="/assets/EntityEditor/EntLocalization.png" alt="Localization" /></p>

<h3 id="属性">属性</h3>

<table>
  <thead>
    <tr>
      <th>プロパティ</th>
      <th>説明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>name</strong></td>
      <td>属性名（Java のアクセサに対応します）</td>
    </tr>
    <tr>
      <td><strong>columnName</strong></td>
      <td>データベースのカラム</td>
    </tr>
    <tr>
      <td><strong>isPrimaryKey</strong></td>
      <td>主キーの一部かどうか</td>
    </tr>
    <tr>
      <td><strong>isClassProperty</strong></td>
      <td>Java のプロパティとして公開されるかどうか</td>
    </tr>
    <tr>
      <td><strong>allowsNull</strong></td>
      <td>カラムが <code class="language-plaintext highlighter-rouge">NULL</code> を許可するかどうか</td>
    </tr>
    <tr>
      <td><strong>prototype</strong></td>
      <td>データベースのプロトタイプ</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p><strong>知っておくと便利:</strong> <strong>isClassProperty</strong> が付いた属性だけが Java のアクセサを持ちます。
テーブルには存在するがクラスプロパティではないカラム（たとえば生の外部キーカラム）は、
モデルには残りますが、EO のメソッドとしては現れません。</p>
</blockquote>

<blockquote>
  <p><strong>プロトタイプとは?</strong> プロトタイプは、カラムのデータベース型・Java の値型・幅をまとめた
名前付きテンプレートです。それぞれを手で設定する代わりに、プロトタイプ（<code class="language-plaintext highlighter-rouge">uuid</code>、
<code class="language-plaintext highlighter-rouge">varchar255</code>、<code class="language-plaintext highlighter-rouge">date</code> など）を選ぶと、属性がそれらをすべて引き継ぎます。覚えておきたい
落とし穴が 1 つあります。<strong><code class="language-plaintext highlighter-rouge">uuid</code></strong> プロトタイプはカラム名を既定で <code class="language-plaintext highlighter-rouge">uuid</code> にするため、
<code class="language-plaintext highlighter-rouge">uuid</code> の主キーや外部キーでは <strong><code class="language-plaintext highlighter-rouge">columnName = id</code></strong> を明示的に設定しなければなりません。
さもないと、生成される SQL が <em>“column uuid does not exist”</em> で失敗します。</p>
</blockquote>

<h4 id="ベーシックパネル-1">ベーシック・パネル</h4>

<p><img src="/assets/EntityEditor/AttBasic.png" alt="Basic" /></p>

<h4 id="アドバンストパネル-1">アドバンスト・パネル</h4>

<p><img src="/assets/EntityEditor/AttAdvanced.png" alt="Advanced" /></p>

<h4 id="ドキュメントパネル">ドキュメント・パネル</h4>

<p><img src="/assets/EntityEditor/AttDocumentation.png" alt="Documentation" /></p>

<h3 id="リレーションシップ">リレーションシップ</h3>

<table>
  <thead>
    <tr>
      <th>プロパティ</th>
      <th>説明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>name</strong></td>
      <td>リレーションシップ名</td>
    </tr>
    <tr>
      <td><strong>destination</strong></td>
      <td>参照先のエンティティ</td>
    </tr>
    <tr>
      <td><strong>isToMany</strong></td>
      <td>to-one（単一オブジェクト）か to-many（配列）か</td>
    </tr>
    <tr>
      <td><strong>deleteRule</strong></td>
      <td>削除時に相手側をどうするか: <code class="language-plaintext highlighter-rouge">Nullify</code>、<code class="language-plaintext highlighter-rouge">Cascade</code>、<code class="language-plaintext highlighter-rouge">Deny</code>、<code class="language-plaintext highlighter-rouge">No Action</code></td>
    </tr>
  </tbody>
</table>

<h4 id="ベーシックパネル-2">ベーシック・パネル</h4>

<p><img src="/assets/EntityEditor/RelBasic.png" alt="Basic" /></p>

<h4 id="アドバンストパネル-2">アドバンスト・パネル</h4>

<p><img src="/assets/EntityEditor/RelAdvanced.png" alt="Advanced" /></p>

<hr />

<h2 id="エンティティハッシュ">エンティティハッシュ</h2>

<p>ツールバーには、選択中のエンティティの小さな <strong>ハッシュ</strong> が表示されます。これはエンティティの
構造 — 属性・リレーションシップ・型 — の指紋です。その色は、最後に保存したマイグレーション
以降に構造が変わったかどうかを示します。</p>

<ul>
  <li><strong>グレー</strong> – 保存済みのハッシュと一致（構造変更なし）</li>
  <li><strong>オレンジ</strong> – 保存済みのハッシュと相違（構造が変わった — 新しいマイグレーションがおそらく必要）</li>
  <li><strong>ブルー</strong> – 新規、保存済みのハッシュがまだない</li>
</ul>

<p>ハッシュをクリックするとクリップボードにコピーされます。</p>

<p><img src="/assets/EntityEditor/Hash.png" alt="Hash" /></p>

<blockquote>
  <p><strong>知っておくと便利:</strong> ハッシュは、データベースをモデルと同期させておくためのリマインダー
です。<strong>オレンジ</strong> になったら、それが <strong>Generate Migration</strong> を押す合図です。</p>
</blockquote>

<hr />

<h2 id="モデルからコードへ--generate-eo">モデルからコードへ — Generate EO</h2>

<p><strong>Generate EO</strong> は、<strong>Template Path</strong> で設定した Velocity テンプレートを使って、モデルを Java
に変換します。これが <a href="/intellij/2026/08/15/ij-project-layout-ja.html">プロジェクト構成</a> の記事で
触れた <code class="language-plaintext highlighter-rouge">generated/</code> フォルダを埋めるものです。各エンティティごとに、KVC のアクセサと
リレーションシップを持つ <strong>アンダースコア始まりのベースクラス</strong>（<code class="language-plaintext highlighter-rouge">_MyEntity.java</code>）が
書き出されます。これらは編集しないでください — 再生成すると上書きされます。あなたの
ビジネスロジックは、<code class="language-plaintext highlighter-rouge">java</code> フォルダにある、対応する <strong><code class="language-plaintext highlighter-rouge">MyEntity.java</code></strong> サブクラスに書きます。
このクラスは生成されたベースクラスを継承します。</p>

<p>つまり、日々の流れはこうです。</p>

<ol>
  <li>ツリーでエンティティを編集する。</li>
  <li>ハッシュが <strong>オレンジ</strong> になるのを確認する。</li>
  <li><strong>Generate Migration</strong> でデータベースを追従させる。</li>
  <li><strong>Generate EO</strong> で Java クラスを追従させる。</li>
  <li><strong>Save</strong>。</li>
</ol>

<hr />

<h2 id="関連">関連</h2>

<ul>
  <li><a href="/intellij/2026/08/15/ij-project-layout-ja.html">プロジェクト構成</a> — <code class="language-plaintext highlighter-rouge">.eomodeld</code> が置かれている場所</li>
  <li><strong>Migration Editor</strong> — このエディタが生成するマイグレーションファイルの編集 <em>(次の記事)</em></li>
</ul>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><category term="日本語" /><summary type="html"><![CDATA[エンティティエディタ]]></summary></entry><entry><title type="html">The Entity Editor</title><link href="https://blog.treasureboat.org/intellij/2026/08/16/ij-entity-editor.html" rel="alternate" type="text/html" title="The Entity Editor" /><published>2026-08-16T00:00:00+09:00</published><updated>2026-08-16T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/16/ij-entity-editor</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/16/ij-entity-editor.html"><![CDATA[<h1 id="the-entity-editor">The Entity Editor</h1>

<p>In the <a href="/intellij/2026/08/15/ij-project-layout.html">Project Layout</a> post we saw the
<code class="language-plaintext highlighter-rouge">resources</code> folder holds an <code class="language-plaintext highlighter-rouge">.eomodeld</code> — the <strong>EO Model</strong>. This post is about the
editor you use to work with it.</p>

<p>An <strong>EOModel</strong> is TreasureBoat’s object-relational mapping: it describes your
entities (tables), their attributes (columns), and the relationships (joins)
between them — declaratively, as data, not as annotations in your Java code.
Open an <code class="language-plaintext highlighter-rouge">.eomodeld</code> and the plugin gives you a visual <strong>Entity Editor</strong> instead
of raw plist files.</p>

<h2 id="what-an-eomodel-is">What an EOModel is</h2>

<p>An <code class="language-plaintext highlighter-rouge">.eomodeld</code> is not a single file — it is a <strong>bundle</strong> (a folder) of plist
files in NeXTSTEP format:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">index.eomodeld</code> – the model metadata (connection info, naming conventions)</li>
  <li>one <code class="language-plaintext highlighter-rouge">.plist</code> per entity – that entity’s attributes, relationships and fetch specs</li>
</ul>

<p>You never have to edit those plists by hand. That is what the editor is for.</p>

<p><img src="/assets/EntityEditor/Overview.png" alt="Overview" /></p>

<hr />

<h2 id="editor-layout">Editor Layout</h2>

<p>The editor has two panels: the <strong>tree</strong> on the left and the <strong>property panel</strong>
on the right.</p>

<h3 id="entity-tree-left">Entity Tree (left)</h3>

<p>The tree shows the whole model structure:</p>

<ul>
  <li><strong>Model</strong> – the <code class="language-plaintext highlighter-rouge">.eomodeld</code> bundle (root)
    <ul>
      <li><strong>Entity</strong> – each entity in the model
        <ul>
          <li><strong>Attributes</strong> – the columns</li>
          <li><strong>Relationships</strong> – the joins to other entities</li>
          <li><strong>Fetch Specifications</strong> – predefined, named queries</li>
          <li><strong>Indexes</strong> – database indexes</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<p>Right-click a node to add or delete entities, attributes, relationships, fetch
specs and indexes, or to create a <strong>subclass</strong> of an entity.</p>

<p><img src="/assets/EntityEditor/EntityTreeRightClick.png" alt="EntityTreeRightClick" /></p>

<p>Also you can create following files when needed:</p>

<ul>
  <li>Create REST Controller…</li>
  <li>Create Sangria Rules…</li>
  <li>Create Sangria Delegate…</li>
</ul>

<h3 id="property-panel-right">Property Panel (right)</h3>

<p>Select any node and the right panel shows its properties for editing — the
attribute’s column and type, the relationship’s destination and delete rule,
and so on.</p>

<p><img src="/assets/EntityEditor/Layout.png" alt="Layout" /></p>

<hr />

<h2 id="toolbar">Toolbar</h2>

<table>
  <thead>
    <tr>
      <th>Button</th>
      <th>What it does</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Save</strong></td>
      <td>Write all changes back to the <code class="language-plaintext highlighter-rouge">.eomodeld</code> plists</td>
    </tr>
    <tr>
      <td><strong>Add Attribute</strong></td>
      <td>Add a column to the selected entity</td>
    </tr>
    <tr>
      <td><strong>Add Relationship</strong></td>
      <td>Add a join from the selected entity</td>
    </tr>
    <tr>
      <td><strong>Generate Migration</strong></td>
      <td>Create a migration file for the model changes (see below)</td>
    </tr>
    <tr>
      <td><strong>Generate EO</strong></td>
      <td>Generate the Java classes from the model</td>
    </tr>
    <tr>
      <td><strong>Verify</strong></td>
      <td>Check the model for consistency errors before you save</td>
    </tr>
    <tr>
      <td><strong>Select in Project View</strong></td>
      <td>Jump to the <code class="language-plaintext highlighter-rouge">.eomodeld</code> folder in the Project View</td>
    </tr>
    <tr>
      <td><strong>Template Path</strong></td>
      <td>Choose the Velocity templates used by <em>Generate EO</em></td>
    </tr>
    <tr>
      <td><strong>Help</strong></td>
      <td>Open this editor’s built-in help</td>
    </tr>
  </tbody>
</table>

<p><img src="/assets/EntityEditor/Toolbar.png" alt="Toolbar" /></p>

<hr />

<h2 id="the-properties-that-matter">The properties that matter</h2>

<h3 id="entity">Entity</h3>

<table>
  <thead>
    <tr>
      <th>Property</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>name</strong></td>
      <td>The entity name (maps to a Java class)</td>
    </tr>
    <tr>
      <td><strong>tableName</strong></td>
      <td>The database table</td>
    </tr>
    <tr>
      <td><strong>className</strong></td>
      <td>The fully-qualified Java class name</td>
    </tr>
    <tr>
      <td><strong>parentName</strong></td>
      <td>Parent entity, for inheritance</td>
    </tr>
    <tr>
      <td><strong>isAbstractEntity</strong></td>
      <td>Abstract entity — no table of its own</td>
    </tr>
  </tbody>
</table>

<h4 id="basic-panel">Basic Panel</h4>

<p><img src="/assets/EntityEditor/EntBasic.png" alt="Basic" /></p>

<h4 id="advanced-panel">Advanced Panel</h4>

<p><img src="/assets/EntityEditor/EntAdvanced.png" alt="Advanced" /></p>

<h4 id="localization-panel">Localization Panel</h4>

<p><img src="/assets/EntityEditor/EntLocalization.png" alt="Localization" /></p>

<h3 id="attribute">Attribute</h3>

<table>
  <thead>
    <tr>
      <th>Property</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>name</strong></td>
      <td>The attribute name (maps to a Java accessor)</td>
    </tr>
    <tr>
      <td><strong>columnName</strong></td>
      <td>The database column</td>
    </tr>
    <tr>
      <td><strong>isPrimaryKey</strong></td>
      <td>Part of the primary key</td>
    </tr>
    <tr>
      <td><strong>isClassProperty</strong></td>
      <td>Whether it is exposed as a Java property</td>
    </tr>
    <tr>
      <td><strong>allowsNull</strong></td>
      <td>Whether the column accepts <code class="language-plaintext highlighter-rouge">NULL</code></td>
    </tr>
    <tr>
      <td><strong>prototype</strong></td>
      <td>The database prototype.</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p><strong>Good to know:</strong> only attributes marked <strong>isClassProperty</strong> get a Java
accessor. A column that exists in the table but is not a class property (a raw
foreign-key column, for example) stays in the model but never shows up as a
method on your EO.</p>
</blockquote>

<blockquote>
  <p><strong>What is a prototype?</strong> A prototype is a named template that bundles a
column’s database type, Java value type and width together. Instead of setting
each of those by hand, you pick a prototype (<code class="language-plaintext highlighter-rouge">uuid</code>, <code class="language-plaintext highlighter-rouge">varchar255</code>, <code class="language-plaintext highlighter-rouge">date</code>, …)
and the attribute inherits all of it. One gotcha worth remembering: the
<strong><code class="language-plaintext highlighter-rouge">uuid</code></strong> prototype defaults the column name to <code class="language-plaintext highlighter-rouge">uuid</code>, so for a <code class="language-plaintext highlighter-rouge">uuid</code>
primary or foreign key you must set <strong><code class="language-plaintext highlighter-rouge">columnName = id</code></strong> explicitly — otherwise
the generated SQL fails with <em>“column uuid does not exist”</em>.</p>
</blockquote>

<h4 id="basic-panel-1">Basic Panel</h4>

<p><img src="/assets/EntityEditor/AttBasic.png" alt="Basic" /></p>

<h4 id="advanced-panel-1">Advanced Panel</h4>

<p><img src="/assets/EntityEditor/AttAdvanced.png" alt="Advanced" /></p>

<h4 id="documentation-panel">Documentation Panel</h4>

<p><img src="/assets/EntityEditor/AttDocumentation.png" alt="Documentation" /></p>

<h3 id="relationship">Relationship</h3>

<table>
  <thead>
    <tr>
      <th>Property</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>name</strong></td>
      <td>The relationship name</td>
    </tr>
    <tr>
      <td><strong>destination</strong></td>
      <td>The target entity</td>
    </tr>
    <tr>
      <td><strong>isToMany</strong></td>
      <td>To-one (a single object) or to-many (an array)</td>
    </tr>
    <tr>
      <td><strong>deleteRule</strong></td>
      <td>What happens to the other side on delete: <code class="language-plaintext highlighter-rouge">Nullify</code>, <code class="language-plaintext highlighter-rouge">Cascade</code>, <code class="language-plaintext highlighter-rouge">Deny</code>, <code class="language-plaintext highlighter-rouge">No Action</code></td>
    </tr>
  </tbody>
</table>

<h4 id="basic-panel-2">Basic Panel</h4>

<h4 id="advanced-panel-2">Advanced Panel</h4>

<p><img src="/assets/EntityEditor/RelBasic.png" alt="Basic" /></p>

<p><img src="/assets/EntityEditor/RelAdvanced.png" alt="Advanced" /></p>

<hr />

<h2 id="the-entity-hash">The Entity Hash</h2>

<p>The toolbar shows a small <strong>hash</strong> for the selected entity. It is a fingerprint
of the entity’s structure — its attributes, relationships and types. Its colour
tells you whether the structure has changed since the last saved migration:</p>

<ul>
  <li><strong>Gray</strong> – matches the saved hash (no structural change)</li>
  <li><strong>Orange</strong> – differs from the saved hash (structure changed — you probably need a new migration)</li>
  <li><strong>Blue</strong> – new, no saved hash yet</li>
</ul>

<p>Click the hash to copy it to the clipboard.</p>

<p><img src="/assets/EntityEditor/Hash.png" alt="Hash" /></p>

<blockquote>
  <p><strong>Good to know:</strong> the hash is your reminder to keep the database in step with
the model. When it turns <strong>orange</strong>, that is the cue to press <strong>Generate
Migration</strong>.</p>
</blockquote>

<hr />

<h2 id="from-model-to-code--generate-eo">From model to code — Generate EO</h2>

<p><strong>Generate EO</strong> turns the model into Java, using the Velocity templates set by
<strong>Template Path</strong>. This is what fills the <code class="language-plaintext highlighter-rouge">generated/</code> folder from the
<a href="/intellij/2026/08/15/ij-project-layout.html">Project Layout</a> post: for each
entity it writes an <strong>underscore base class</strong> (<code class="language-plaintext highlighter-rouge">_MyEntity.java</code>) with the KVC
accessors and relationships. You never edit those — regenerating overwrites
them. Your business logic goes in the matching <strong><code class="language-plaintext highlighter-rouge">MyEntity.java</code></strong> subclass under
<code class="language-plaintext highlighter-rouge">java</code>, which extends the generated base.</p>

<p>So the everyday loop is:</p>

<ol>
  <li>Edit the entity in the tree.</li>
  <li>Watch the hash go <strong>orange</strong>.</li>
  <li><strong>Generate Migration</strong> to bring the database along.</li>
  <li><strong>Generate EO</strong> to bring the Java classes along.</li>
  <li><strong>Save</strong>.</li>
</ol>

<hr />

<h2 id="related">Related</h2>

<ul>
  <li><a href="/intellij/2026/08/15/ij-project-layout.html">Project Layout</a> — where the <code class="language-plaintext highlighter-rouge">.eomodeld</code> lives</li>
  <li>The <strong>Migration Editor</strong> — editing the migration files this editor generates <em>(next post)</em></li>
</ul>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><summary type="html"><![CDATA[The Entity Editor]]></summary></entry><entry xml:lang="ja"><title type="html">IntelliJ IDEA のプロジェクト構成</title><link href="https://blog.treasureboat.org/intellij/2026/08/15/ij-project-layout-ja.html" rel="alternate" type="text/html" title="IntelliJ IDEA のプロジェクト構成" /><published>2026-08-15T00:00:00+09:00</published><updated>2026-08-15T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/15/ij-project-layout-ja</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/15/ij-project-layout-ja.html"><![CDATA[<h1 id="intellij-プロジェクト構成">IntelliJ プロジェクト構成</h1>

<p>まずはフレームワークプロジェクトの構成を見ていきましょう。<br />
この例では <strong>tb-pro-rule-engine</strong> を使います。</p>

<h2 id="概要">概要</h2>

<p><img src="/assets/ProjectLayout/TopLayout.png" alt="TopLayout" /></p>

<ul>
  <li>.idea – IntelliJ がセットアップや設定を管理するためのフォルダです</li>
  <li>docs – .sangria ルールのバックアップファイルが保存される、任意のフォルダです</li>
  <li>Documents – こちらもドキュメント用の、任意のフォルダです</li>
  <li>src – 実際のプロジェクトフォルダです（開発・コンパイル）</li>
  <li>target – <strong>src</strong> フォルダをコンパイルした結果が入るフォルダです（デプロイ用）。ビルド時にはバンドルの <strong>Info.plist</strong> もここに生成されます（実行ファイル名・プリンシパルクラス・バージョンといった、バンドルメタデータの唯一の正となる情報源です）。そのため Info.plist は <strong>src</strong> には見当たりません。</li>
  <li>.treasureboat – プロジェクトの情報（アプリケーションかフレームワークか）を持つファイルです。旧来の（変換された）プロジェクトがバンドル識別に使っていた Eclipse の <code class="language-plaintext highlighter-rouge">build.properties</code> を置き換えるものです。</li>
  <li>pom.xml – ビルドファイル（Maven）です。依存関係、TreasureBoat フレームワークのバージョン、ビルドプロファイルを記述します。</li>
  <li>pom.xml.versionsBackup – <code class="language-plaintext highlighter-rouge">versions:set</code>（リリースバージョンの更新など）を実行したときに Maven が作成するバックアップです。削除して構いません。</li>
  <li>{プロジェクト名}.iml – IntelliJ がプロジェクト情報を管理するために使うファイルです</li>
</ul>

<hr />

<h2 id="プロジェクト構成">プロジェクト構成</h2>

<p><strong>src</strong> フォルダの中には、<strong>test</strong> と <strong>main</strong> の 2 つがあります。</p>

<p><img src="/assets/ProjectLayout/src.png" alt="src" /></p>

<hr />

<h3 id="test">test</h3>

<p><strong>test</strong> フォルダにはプロジェクトのユニットテストが入ります。<br />
TreasureBoat は <strong>JUnit 5</strong> によるユニットテストに対応しています。</p>

<ul>
  <li>java – ユニットテストの Java ソースコードが入ります</li>
  <li>resources – プロジェクトのリソース（画像や設定ファイルなど）が入ります</li>
</ul>

<p><img src="/assets/ProjectLayout/test.png" alt="test" /></p>

<hr />

<h3 id="main">main</h3>

<p><strong>main</strong> フォルダにはプロジェクトのソースコードが入ります。</p>

<ul>
  <li>generated – 自動生成されたコード（生成されたクラスなど）が入ります</li>
  <li>java – プロジェクトの Java ソースコードが入ります</li>
  <li>resources – プロジェクトのリソース（画像や設定ファイルなど）が入ります</li>
  <li>webapp – プロジェクトのコンポーネント（HTML / XML / JS など）が入ります</li>
  <li>webserver-resources – Web サーバー用のリソース（静的ファイルなど）が入ります</li>
</ul>

<p><img src="/assets/ProjectLayout/main.png" alt="main" /></p>

<hr />

<h3 id="generated">generated</h3>

<p>ここには自動生成されたコード（生成されたクラスなど）が入ります。<br />
TreasureBoat では、生成コードはフレームワークによって自動生成されるものであり、ユーザーが手で編集するものではありません。<br />
これらのファイルは Entity Editor の EOGenerator によって生成されます。</p>

<p>各エンティティごとに、KVC のアクセサやリレーションシップを持つ <strong>アンダースコア始まりのベースクラス</strong>（例：<code class="language-plaintext highlighter-rouge">_MyEntity.java</code>）がここに生成されます。これらは絶対に編集しないでください — 再生成のたびに上書きされてしまいます。あなたのビジネスロジックは、<strong>java</strong> フォルダにある、対応する <strong>アンダースコアなしのサブクラス</strong>（<code class="language-plaintext highlighter-rouge">MyEntity.java</code>）に書きます。このクラスは生成されたベースクラスを継承しています。この分割のおかげで、自分のコードを失うことなくモデルを再生成できます。</p>

<p><img src="/assets/ProjectLayout/generated.png" alt="generated" /></p>

<hr />

<h3 id="java">java</h3>

<p>ここにはプロジェクトのすべてのソースコードが入ります。</p>

<p><img src="/assets/ProjectLayout/java.png" alt="java" /></p>

<hr />

<h3 id="resources">resources</h3>

<p>アプリケーションが必要とするすべてのリソースを置くフォルダです。</p>

<h5 id="ローカライズファイル">ローカライズファイル</h5>

<ul>
  <li>Chinese_Taiwan.lproj – 中国語（台湾）のローカライズファイル</li>
  <li>Dutch.lproj – オランダ語のローカライズファイル</li>
  <li>English.lproj – 英語のローカライズファイル</li>
  <li>French.lproj – フランス語のローカライズファイル</li>
  <li>German.lproj – ドイツ語のローカライズファイル</li>
  <li>Italian.lproj – イタリア語のローカライズファイル</li>
  <li>Japanese.lproj – 日本語のローカライズファイル</li>
  <li>Portuguese_Brazil.lproj – ポルトガル語（ブラジル）のローカライズファイル</li>
  <li>Spanish.lproj – スペイン語のローカライズファイル</li>
</ul>

<h5 id="eo-マイグレーションファイル">EO マイグレーションファイル</h5>

<ul>
  <li>EOMigration – 起動時にデータを読み込むための EO マイグレーションファイル</li>
  <li>EOTestMigration – マイグレーションファイルを開発するための、EO マイグレーションのテスト用ファイル</li>
</ul>

<h5 id="ナビゲーション">ナビゲーション</h5>

<ul>
  <li>Navigationbar – ナビゲーションバーの設定</li>
</ul>

<h5 id="モデル">モデル</h5>

<ul>
  <li>tb_pro_rule_engine_model.eomodeld – EO モデル</li>
</ul>

<h5 id="sangria">Sangria</h5>

<ul>
  <li>d2w.sangria – Sangria のルールファイル（NeXTSTEP plist 形式）です。ルールの条件（LHS）<code class="language-plaintext highlighter-rouge">=&gt;</code> プロパティ値（RHS）を記述し、ルールベースの UI を制御します。概要で触れた <strong>docs</strong> フォルダには、このファイルのタイムスタンプ付きバックアップが保存されます。</li>
</ul>

<h5 id="プロパティ">プロパティ</h5>

<ul>
  <li>Properties.properties – プロパティファイル</li>
</ul>

<p><img src="/assets/ProjectLayout/resources.png" alt="resources" /></p>

<hr />

<h3 id="webapp">webapp</h3>

<p>ここにはプロジェクトのすべてのコンポーネント（HTML / XML / JS など）が入ります。</p>

<p>各コンポーネントは <strong><code class="language-plaintext highlighter-rouge">.wo</code> フォルダ</strong> です。これは、1 つのコンポーネントを構成する各ファイルをまとめた小さなバンドルです。</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">.html</code> – テンプレート。動的なプレースホルダとして <code class="language-plaintext highlighter-rouge">&lt;treasureboat&gt;</code>（または <code class="language-plaintext highlighter-rouge">&lt;tb:...&gt;</code>）タグを使います</li>
  <li><code class="language-plaintext highlighter-rouge">.wod</code> – <em>(任意)</em> それらのタグを KVC キーパス経由で Java コードに結びつけるバインディング</li>
  <li><code class="language-plaintext highlighter-rouge">.api</code> – <em>(任意)</em> Component Editor 向けに、コンポーネントのバインディングを宣言します</li>
  <li><code class="language-plaintext highlighter-rouge">.md</code> – <em>(任意)</em> コンポーネントのドキュメント</li>
</ul>

<p>このフォルダ内の構成は自由です。好きなようにコンポーネントをグループ分けできます。</p>

<p>古い実装の名残で NonLocalized.lproj フォルダが残っている場合がありますが、現在はもう必要ありません。<br />
TreasureBoat は多言語コンポーネントには対応していません。<br />
ローカライズには localizer クラスを使ってください。</p>

<p><img src="/assets/ProjectLayout/webapp.png" alt="webapp" /></p>

<hr />

<h3 id="webserver-resources">webserver-resources</h3>

<p>ここには Web サーバー用のリソース、つまりアプリケーションを介さずに Web サーバーが直接配信する静的ファイル（CSS・JS・画像・フォントなど）が入ります。</p>

<p>これらを参照するには、所有するフレームワーク名と <code class="language-plaintext highlighter-rouge">webserver-resources</code> 内のパスを指定した <strong><code class="language-plaintext highlighter-rouge">static://</code></strong> URL を使います。例：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>static://tb-core-skin-keen:assets/css/style.bundle.css
</code></pre></div></div>

<p>フレームワーク名が URL の一部になっているため、1 つのバンドルが、それに依存するすべてのアプリにアセットを配信できます。これが、スキンが CDN を使わずに CSS / JS をすべてのアプリへ届ける仕組みです。</p>

<p><img src="/assets/ProjectLayout/webserver-resources.png" alt="webserver-resources" /></p>

<hr />

<h2 id="アプリケーション-と-フレームワーク">アプリケーション と フレームワーク</h2>

<p>概要に出てきた <code class="language-plaintext highlighter-rouge">.treasureboat</code> ファイルには、プロジェクトが <strong>アプリケーション</strong> なのか <strong>フレームワーク</strong> なのかが記録されています。両者は、いま見てきた構成 — <code class="language-plaintext highlighter-rouge">generated</code>・<code class="language-plaintext highlighter-rouge">java</code>・<code class="language-plaintext highlighter-rouge">resources</code>・<code class="language-plaintext highlighter-rouge">webapp</code>・<code class="language-plaintext highlighter-rouge">webserver-resources</code> を含む <code class="language-plaintext highlighter-rouge">src/main</code> — を <strong>まったく同じように</strong> 共有しています。違うのは、バンドルが <strong>何であるか</strong>、そしてどう動くかです。</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>フレームワーク</th>
      <th>アプリケーション</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>目的</td>
      <td>他のプロジェクトが依存するライブラリ — モデル・コンポーネント・スキン・機能</td>
      <td>フレームワークを束ねて動作する、実行可能なアプリ</td>
    </tr>
    <tr>
      <td>バンドル種別</td>
      <td><code class="language-plaintext highlighter-rouge">FMWK</code> — <code class="language-plaintext highlighter-rouge">.framework</code>。Maven の依存関係として取り込まれます</td>
      <td><code class="language-plaintext highlighter-rouge">APPL</code> — JAR と起動スクリプトを含む、実行可能な <code class="language-plaintext highlighter-rouge">.woa</code> バンドル</td>
    </tr>
    <tr>
      <td>プリンシパルクラス</td>
      <td><code class="language-plaintext highlighter-rouge">TBEnterpriseFrameworkPrincipal</code> を継承 — バンドル読み込み時に実行されるセットアップ用フック</td>
      <td>アプリの <code class="language-plaintext highlighter-rouge">Application</code> クラス（<code class="language-plaintext highlighter-rouge">TBApplication</code> を継承）— エントリーポイント</td>
    </tr>
    <tr>
      <td>Info.plist（<strong>target</strong> 内）</td>
      <td><code class="language-plaintext highlighter-rouge">target/classes/Resources/Info.plist</code></td>
      <td><code class="language-plaintext highlighter-rouge">target/classes/Info.plist</code></td>
    </tr>
    <tr>
      <td>典型的な <code class="language-plaintext highlighter-rouge">resources</code></td>
      <td>利用側が使う、共有の EO モデル・コンポーネント・マイグレーション</td>
      <td>上記に <strong>加えて</strong>、実際のデプロイ用 Properties（DB 接続）、起動時 EO マイグレーション、アプリ設定</td>
    </tr>
  </tbody>
</table>

<p>この例の <strong>tb-pro-rule-engine</strong> はフレームワークで、アプリケーションが依存するルールエンジンのモデルとコンポーネントを提供します。アプリケーションはこれ（と他の多くのフレームワーク）に依存し、その上に独自の画面・データ・デプロイ設定を追加します。</p>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><category term="日本語" /><summary type="html"><![CDATA[IntelliJ プロジェクト構成]]></summary></entry><entry><title type="html">IntelliJ IDEA Project Layout</title><link href="https://blog.treasureboat.org/intellij/2026/08/15/ij-project-layout.html" rel="alternate" type="text/html" title="IntelliJ IDEA Project Layout" /><published>2026-08-15T00:00:00+09:00</published><updated>2026-08-15T00:00:00+09:00</updated><id>https://blog.treasureboat.org/intellij/2026/08/15/ij-project-layout</id><content type="html" xml:base="https://blog.treasureboat.org/intellij/2026/08/15/ij-project-layout.html"><![CDATA[<h1 id="intellij-project-layout">IntelliJ Project Layout</h1>

<p>So let’s take a first look at a framework project layout.<br />
In this example we use <strong>tb-pro-rule-engine</strong>.</p>

<h2 id="overview">Overview</h2>

<p><img src="/assets/ProjectLayout/TopLayout.png" alt="TopLayout" /></p>

<ul>
  <li>.idea - A folder is the IntelliJ maintenance folder for all the setup and configuration</li>
  <li>docs - A folder is an optional folder where .sangria rule backup files get saved</li>
  <li>Documents – Also, here is an optional folder for your Documentation</li>
  <li>src – This is the real project folder (development/compile)</li>
  <li>target – The target folder is the compiled version of the <strong>src</strong> folder (deploy). The build also generates the bundle’s <strong>Info.plist</strong> in here (the single source of truth for bundle metadata — executable name, principal class, version), which is why you won’t find Info.plist in <strong>src</strong>.</li>
  <li>.treasureboat - This file has information about the project (Application or Framework). It replaces the legacy Eclipse <code class="language-plaintext highlighter-rouge">build.properties</code> that older, converted projects used for bundle identification.</li>
  <li>pom.xml – The build file (Maven): dependencies, the TreasureBoat framework versions, and the build profiles.</li>
  <li>pom.xml.versionsBackup – A backup Maven writes when you run <code class="language-plaintext highlighter-rouge">versions:set</code> (e.g. bumping the release version). Safe to delete.</li>
  <li>{Project Name}.iml – A file that is used by IntelliJ for tracking project information</li>
</ul>

<hr />

<h2 id="project-layout">Project Layout</h2>

<p>Inside the <strong>src</strong> folder you will find the following: <strong>test</strong> and <strong>main</strong></p>

<p><img src="/assets/ProjectLayout/src.png" alt="src" /></p>

<hr />

<h3 id="test">test</h3>

<p>The <strong>test</strong> folder contains the unit tests for the project.<br />
TreasureBoat supports <strong>JUnit 5</strong> unit testing.</p>

<ul>
  <li>java – This folder contains the Java source code for the unit tests.</li>
  <li>resources – This folder contains the resources for the project (e.g., images, configuration files, etc.)</li>
</ul>

<p><img src="/assets/ProjectLayout/test.png" alt="test" /></p>

<hr />

<h3 id="main">main</h3>

<p>The <strong>main</strong> folder contains the source code for the project.</p>

<ul>
  <li>generated – This folder contains the generated code for the project (e.g., generated classes, etc.)</li>
  <li>java – This folder contains the Java source code for the project.</li>
  <li>resources – This folder contains the resources for the project (e.g., images, configuration files, etc.)</li>
  <li>webapp – This folder contains the Components (HTML/XML/JS …) for the project.</li>
  <li>webserver-resources – This folder contains the web server resources for the project (e.g., static files, etc.)</li>
</ul>

<p><img src="/assets/ProjectLayout/main.png" alt="main" /></p>

<hr />

<h3 id="generated">generated</h3>

<p>Here you can find the generated code for the project (e.g., generated classes, etc.)<br />
In TreasureBoat, the generated code is automatically generated by the framework and is not meant to be modified by the user.<br />
Those files get generated by the Entity Editor EOGenerator.</p>

<p>Each entity produces an <strong>underscore-prefixed base class</strong> here (e.g. <code class="language-plaintext highlighter-rouge">_MyEntity.java</code>) that holds the KVC accessors and relationships. Never edit these — regenerating overwrites them. Your business logic goes in the matching <strong>non-underscore subclass</strong> (<code class="language-plaintext highlighter-rouge">MyEntity.java</code>) under <strong>java</strong>, which extends the generated base. This split lets you re-generate the model without losing your code.</p>

<p><img src="/assets/ProjectLayout/generated.png" alt="generated" /></p>

<hr />

<h3 id="java">java</h3>

<p>Here you can find all your Source Code for the project.</p>

<p><img src="/assets/ProjectLayout/java.png" alt="java" /></p>

<hr />

<h3 id="resources">resources</h3>

<p>This is the folder for all the resources that are needed by the application.</p>

<h5 id="localization-files">Localization Files</h5>

<ul>
  <li>Chinese_Taiwan.lproj – Chinese Localization File</li>
  <li>Dutch.lproj – Dutch Localization File</li>
  <li>English.lproj – English Localization File</li>
  <li>French.lproj – French Localization File</li>
  <li>German.lproj – German Localization File</li>
  <li>Italian.lproj – Italian Localization File</li>
  <li>Japanese.lproj – Japanese Localization File</li>
  <li>Portuguese_Brazil.lproj – Brazil Portuguese Localization File</li>
  <li>Spanish.lproj – Spanish Localization File</li>
</ul>

<h5 id="eo-migration-files">EO Migration Files</h5>

<ul>
  <li>EOMigration – The EO Migration Files for loading data at boot time</li>
  <li>EOTestMigration – The EO Migration Test file for developing Migration Files</li>
</ul>

<h5 id="navigation">Navigation</h5>

<ul>
  <li>Navigationbar - The Navigation-bar configuration</li>
</ul>

<h5 id="model">Model</h5>

<ul>
  <li>tb_pro_rule_engine_model.eomodeld – The EO Model</li>
</ul>

<h5 id="sangria">Sangria</h5>

<ul>
  <li>d2w.sangria – The Sangria rule file (NeXTSTEP plist format): rule conditions (LHS) <code class="language-plaintext highlighter-rouge">=&gt;</code> property values (RHS) that drive the rule-based UI. The <strong>docs</strong> folder mentioned in the Overview keeps timestamped backups of this file.</li>
</ul>

<h5 id="properties">Properties</h5>

<ul>
  <li>Properties.properties – The Properties file</li>
</ul>

<p><img src="/assets/ProjectLayout/resources.png" alt="resources" /></p>

<hr />

<h3 id="webapp">webapp</h3>

<p>Here you can find all your Components for the project (e.g., HTML/XML/JS …)</p>

<p>Each component is a <strong><code class="language-plaintext highlighter-rouge">.wo</code> folder</strong> — a small bundle that groups the parts of one component together:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">.html</code> – the template, using <code class="language-plaintext highlighter-rouge">&lt;treasureboat&gt;</code> (or <code class="language-plaintext highlighter-rouge">&lt;tb:...&gt;</code>) tags as dynamic placeholders</li>
  <li><code class="language-plaintext highlighter-rouge">.wod</code> – <em>(optional)</em>  the bindings that wire those tags to your Java code through KVC keypaths</li>
  <li><code class="language-plaintext highlighter-rouge">.api</code> – <em>(optional)</em> declares the component’s bindings for the Component Editor</li>
  <li><code class="language-plaintext highlighter-rouge">.md</code> – <em>(optional)</em> documentation for the component</li>
</ul>

<p>The folder structure inside this folder is free — group components however you like.</p>

<p>From older implementations there is still a NonLocalized.lproj folder, but it is not necessary anymore.<br />
TreasureBoat is not supporting Multilanguage Components.<br />
For Localization you should use the localizer classes.</p>

<p><img src="/assets/ProjectLayout/webapp.png" alt="webapp" /></p>

<hr />

<h3 id="webserver-resources">webserver-resources</h3>

<p>Here you can find all your web server resources for the project — static files (CSS, JS, images, fonts) that the web server serves directly, not through the application.</p>

<p>Reference them with a <strong><code class="language-plaintext highlighter-rouge">static://</code></strong> URL that names the owning framework and the path inside <code class="language-plaintext highlighter-rouge">webserver-resources</code>, for example:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>static://tb-core-skin-keen:assets/css/style.bundle.css
</code></pre></div></div>

<p>Because the framework name is part of the URL, one bundle can serve its assets to every app that depends on it — this is how a skin ships its CSS/JS to all apps without needing a CDN.</p>

<p><img src="/assets/ProjectLayout/webserver-resources.png" alt="webserver-resources" /></p>

<hr />

<h2 id="application-vs-framework">Application vs Framework</h2>

<p>The <code class="language-plaintext highlighter-rouge">.treasureboat</code> file in the Overview records whether a project is an <strong>Application</strong> or a <strong>Framework</strong>. Both share the <strong>exact same layout</strong> you just saw — <code class="language-plaintext highlighter-rouge">src/main</code> with <code class="language-plaintext highlighter-rouge">generated</code>, <code class="language-plaintext highlighter-rouge">java</code>, <code class="language-plaintext highlighter-rouge">resources</code>, <code class="language-plaintext highlighter-rouge">webapp</code>, and <code class="language-plaintext highlighter-rouge">webserver-resources</code>. What differs is what the bundle <em>is</em> and how it runs:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>Framework</th>
      <th>Application</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Purpose</td>
      <td>A library other projects depend on — models, components, a skin, features</td>
      <td>A runnable app that ties frameworks together</td>
    </tr>
    <tr>
      <td>Bundle type</td>
      <td><code class="language-plaintext highlighter-rouge">FMWK</code> — a <code class="language-plaintext highlighter-rouge">.framework</code>, pulled in as a Maven dependency</td>
      <td><code class="language-plaintext highlighter-rouge">APPL</code> — a runnable <code class="language-plaintext highlighter-rouge">.woa</code> bundle with JARs + run scripts</td>
    </tr>
    <tr>
      <td>Principal class</td>
      <td>extends <code class="language-plaintext highlighter-rouge">TBEnterpriseFrameworkPrincipal</code> — a setup hook that runs when the bundle loads</td>
      <td>the app’s <code class="language-plaintext highlighter-rouge">Application</code> class (extends <code class="language-plaintext highlighter-rouge">TBApplication</code>) — the entry point</td>
    </tr>
    <tr>
      <td>Info.plist (in <strong>target</strong>)</td>
      <td><code class="language-plaintext highlighter-rouge">target/classes/Resources/Info.plist</code></td>
      <td><code class="language-plaintext highlighter-rouge">target/classes/Info.plist</code></td>
    </tr>
    <tr>
      <td>Typical <code class="language-plaintext highlighter-rouge">resources</code></td>
      <td>shared EO models, components and migrations for consumers to use</td>
      <td>the above <strong>plus</strong> real deployment Properties (DB connection), boot-time EO migrations, and app config</td>
    </tr>
  </tbody>
</table>

<p>Our example, <strong>tb-pro-rule-engine</strong>, is a framework: it ships a rule-engine model and components that applications depend on. An application depends on it (and many other frameworks) and adds its own screens, data, and deployment configuration on top.</p>

<hr />]]></content><author><name>ishimoto</name></author><category term="IntelliJ" /><category term="IntelliJ" /><summary type="html"><![CDATA[IntelliJ Project Layout]]></summary></entry></feed>