-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathstack-architecture.html
More file actions
417 lines (369 loc) · 37.4 KB
/
stack-architecture.html
File metadata and controls
417 lines (369 loc) · 37.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
<!DOCTYPE HTML>
<html lang="en" class="light" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Stack Architecture</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<script data-host="https://app.microanalytics.io" data-dnt="false" src="https://app.microanalytics.io/js/script.js" id="ZwSg9rf6GA" async defer></script>
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('light')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ul class="chapter">
<li><a class="active" href="../">chuck-stack Home</a></li> <!--chuboe changed-->
</ul>
<ol class="chapter"><li class="chapter-item expanded "><a href="introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li class="chapter-item expanded "><a href="picture-success.html"><strong aria-hidden="true">2.</strong> Picture of Success</a></li><li class="chapter-item expanded "><a href="success-factor.html"><strong aria-hidden="true">3.</strong> Success Factors</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="success-hr.html"><strong aria-hidden="true">3.1.</strong> Success with HR</a></li><li class="chapter-item expanded "><a href="success-ai.html"><strong aria-hidden="true">3.2.</strong> Success with AI</a></li><li class="chapter-item expanded "><a href="success-cli.html"><strong aria-hidden="true">3.3.</strong> Success with CLI</a></li><li class="chapter-item expanded "><a href="success-linux.html"><strong aria-hidden="true">3.4.</strong> Success with Linux</a></li><li class="chapter-item expanded "><a href="success-postgresql.html"><strong aria-hidden="true">3.5.</strong> Success with PostgreSQL</a></li><li class="chapter-item expanded "><a href="success-api.html"><strong aria-hidden="true">3.6.</strong> Success with API</a></li></ol></li><li class="chapter-item expanded "><a href="getting-started.html"><strong aria-hidden="true">4.</strong> Getting Started</a></li><li class="chapter-item expanded "><a href="stack-faq.html"><strong aria-hidden="true">5.</strong> Stack FAQ</a></li><li class="chapter-item expanded "><a href="stack-tools.html"><strong aria-hidden="true">6.</strong> Stack Tools</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="tool-incus.html"><strong aria-hidden="true">6.1.</strong> Incus</a></li><li class="chapter-item expanded "><a href="tool-linux.html"><strong aria-hidden="true">6.2.</strong> Linux</a></li><li class="chapter-item expanded "><a href="tool-postgresql.html"><strong aria-hidden="true">6.3.</strong> PostgreSQL</a></li><li class="chapter-item expanded "><a href="tool-postgrest.html"><strong aria-hidden="true">6.4.</strong> PostgREST</a></li><li class="chapter-item expanded "><a href="tool-aichat.html"><strong aria-hidden="true">6.5.</strong> AIChat</a></li><li class="chapter-item expanded "><a href="tool-nushell.html"><strong aria-hidden="true">6.6.</strong> Nushell</a></li><li class="chapter-item expanded "><a href="tool-zellij.html"><strong aria-hidden="true">6.7.</strong> Zellij</a></li><li class="chapter-item expanded "><a href="tool-git.html"><strong aria-hidden="true">6.8.</strong> Git</a></li><li class="chapter-item expanded "><a href="tool-obsidian.html"><strong aria-hidden="true">6.9.</strong> Obsidian</a></li><li class="chapter-item expanded "><a href="tool-netbird.html"><strong aria-hidden="true">6.10.</strong> Netbird</a></li><li class="chapter-item expanded "><a href="tool-idempiere.html"><strong aria-hidden="true">6.11.</strong> iDempiere</a></li><li class="chapter-item expanded "><a href="tool-htmx.html"><strong aria-hidden="true">6.12.</strong> htmx</a></li><li class="chapter-item expanded "><a href="tool-discourse.html"><strong aria-hidden="true">6.13.</strong> Discourse</a></li><li class="chapter-item expanded "><a href="tool-mdbook.html"><strong aria-hidden="true">6.14.</strong> mdBook</a></li><li class="chapter-item expanded "><a href="tool-others.html"><strong aria-hidden="true">6.15.</strong> Others</a></li></ol></li><li class="chapter-item expanded "><a href="stack-architecture.html" class="active"><strong aria-hidden="true">7.</strong> Stack Architecture</a></li><li class="chapter-item expanded "><a href="stack-application.html"><strong aria-hidden="true">8.</strong> Stack Application</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="application-deploy.html"><strong aria-hidden="true">8.1.</strong> Deployment</a></li><li class="chapter-item expanded "><a href="application-workflow.html"><strong aria-hidden="true">8.2.</strong> Workflow</a></li><li class="chapter-item expanded "><a href="application-attribute.html"><strong aria-hidden="true">8.3.</strong> Attribute Tagging</a></li></ol></li><li class="chapter-item expanded "><a href="best-practices.html"><strong aria-hidden="true">9.</strong> Stack Best Practices</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="best-practices-operation.html"><strong aria-hidden="true">9.1.</strong> Operation Best Practices</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="best-practices-operation-say.html"><strong aria-hidden="true">9.1.1.</strong> Say What We Do</a></li><li class="chapter-item expanded "><a href="best-practices-operation-do.html"><strong aria-hidden="true">9.1.2.</strong> Do What We Said</a></li><li class="chapter-item expanded "><a href="best-practices-operation-prove.html"><strong aria-hidden="true">9.1.3.</strong> Prove We Did It</a></li><li class="chapter-item expanded "><a href="best-practices-operation-feedback.html"><strong aria-hidden="true">9.1.4.</strong> Welcome Feedback</a></li><li class="chapter-item expanded "><a href="best-practices-operation-improve.html"><strong aria-hidden="true">9.1.5.</strong> Continuously Improve</a></li></ol></li><li class="chapter-item expanded "><a href="data-management-philosophy.html"><strong aria-hidden="true">9.2.</strong> Data Management Philosophy</a></li><li class="chapter-item expanded "><a href="postgres-conventions.html"><strong aria-hidden="true">9.3.</strong> Postgres Conventions</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="postgres-convention/schema.html"><strong aria-hidden="true">9.3.1.</strong> Private and API Schema</a></li><li class="chapter-item expanded "><a href="postgres-convention/abbreviation.html"><strong aria-hidden="true">9.3.2.</strong> Abbreviation</a></li><li class="chapter-item expanded "><a href="postgres-convention/table-convention.html"><strong aria-hidden="true">9.3.3.</strong> Table Convention</a></li><li class="chapter-item expanded "><a href="postgres-convention/column-convention.html"><strong aria-hidden="true">9.3.4.</strong> Column Convention</a></li><li class="chapter-item expanded "><a href="postgres-convention/table-record-convention.html"><strong aria-hidden="true">9.3.5.</strong> Table and Record</a></li><li class="chapter-item expanded "><a href="postgres-convention/uuid.html"><strong aria-hidden="true">9.3.6.</strong> UUID</a></li><li class="chapter-item expanded "><a href="postgres-convention/json-array-table-column.html"><strong aria-hidden="true">9.3.7.</strong> JSON vs Array vs Table</a></li><li class="chapter-item expanded "><a href="postgres-convention/enum-type-convention.html"><strong aria-hidden="true">9.3.8.</strong> enum and Type</a></li><li class="chapter-item expanded "><a href="postgres-convention/partition-convention.html"><strong aria-hidden="true">9.3.9.</strong> Partition</a></li><li class="chapter-item expanded "><a href="postgres-convention/function-convention.html"><strong aria-hidden="true">9.3.10.</strong> Function</a></li><li class="chapter-item expanded "><a href="postgres-convention/trigger-convention.html"><strong aria-hidden="true">9.3.11.</strong> Trigger</a></li><li class="chapter-item expanded "><a href="postgres-convention/comment.html"><strong aria-hidden="true">9.3.12.</strong> Comments</a></li><li class="chapter-item expanded "><a href="postgres-convention/sample-table-convention.html"><strong aria-hidden="true">9.3.13.</strong> Sample Table</a></li><li class="chapter-item expanded "><a href="postgres-convention/scalability-convention.html"><strong aria-hidden="true">9.3.14.</strong> Scalability</a></li><li class="chapter-item expanded "><a href="postgres-convention/nushell.html"><strong aria-hidden="true">9.3.15.</strong> Nushell psql</a></li><li class="chapter-item expanded "><a href="postgres-convention/to-be-resolved-convention.html"><strong aria-hidden="true">9.3.16.</strong> To Be Resolved</a></li></ol></li><li class="chapter-item expanded "><a href="postgres-services.html"><strong aria-hidden="true">9.4.</strong> Postgres Services</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="postgres-convention/async.html"><strong aria-hidden="true">9.4.1.</strong> Async</a></li><li class="chapter-item expanded "><a href="postgres-convention/attribute-tag.html"><strong aria-hidden="true">9.4.2.</strong> Attribute Tagging</a></li><li class="chapter-item expanded "><a href="postgres-convention/change-log.html"><strong aria-hidden="true">9.4.3.</strong> Change Log</a></li><li class="chapter-item expanded "><a href="postgres-convention/event.html"><strong aria-hidden="true">9.4.4.</strong> Event</a></li><li class="chapter-item expanded "><a href="postgres-convention/notify.html"><strong aria-hidden="true">9.4.5.</strong> Notify</a></li><li class="chapter-item expanded "><a href="postgres-convention/request.html"><strong aria-hidden="true">9.4.6.</strong> Request Workflow</a></li><li class="chapter-item expanded "><a href="postgres-convention/statistics-convention.html"><strong aria-hidden="true">9.4.7.</strong> Statistics</a></li><li class="chapter-item expanded "><a href="postgres-convention/system-configuration-convention.html"><strong aria-hidden="true">9.4.8.</strong> System Configuration</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="cli-tutor.html"><strong aria-hidden="true">10.</strong> Stack Tutor</a></li><li class="chapter-item expanded "><a href="stack-academy.html"><strong aria-hidden="true">11.</strong> Stack Academy</a></li><li class="chapter-item expanded "><a href="stack-local.html"><strong aria-hidden="true">12.</strong> Local Community Support</a></li><li class="chapter-item expanded "><a href="terminology.html"><strong aria-hidden="true">13.</strong> Terminology</a></li><li class="chapter-item expanded "><a href="roadmap.html"><strong aria-hidden="true">14.</strong> Roadmap</a></li><li class="chapter-item expanded "><a href="project-history.html"><strong aria-hidden="true">15.</strong> Project History</a></li><li class="chapter-item expanded "><a href="reference.html"><strong aria-hidden="true">16.</strong> References</a></li><li class="chapter-item expanded affix "><li class="spacer"></li><li class="chapter-item expanded "><a href="code-of-conduct.html"><strong aria-hidden="true">17.</strong> Code of Conduct</a></li><li class="chapter-item expanded "><a href="privacy-policy.html"><strong aria-hidden="true">18.</strong> Privacy Policy</a></li><li class="chapter-item expanded affix "><li class="spacer"></li><li class="chapter-item expanded "><a href="blog.html"><strong aria-hidden="true">19.</strong> Blog</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="blog-postgresql-json-show-sales-order.html"><strong aria-hidden="true">19.1.</strong> How to Extract JSON from PostgreSQL</a></li><li class="chapter-item expanded "><a href="blog-incus-netbird-phoenixnap-isolated.html"><strong aria-hidden="true">19.2.</strong> Isolated Public-Facing Services in Incus</a></li><li class="chapter-item expanded "><a href="blog-local-co-op-funding-help.html"><strong aria-hidden="true">19.3.</strong> Local AI Funding - Time to Bring Back the Co-op</a></li><li class="chapter-item expanded "><a href="blog-llm-ai-production-deploy.html"><strong aria-hidden="true">19.4.</strong> Production Open Source Chat with Work Instructions</a></li><li class="chapter-item expanded "><a href="blog-chuck-stack-it-job-description-assessment.html"><strong aria-hidden="true">19.5.</strong> chuck-stack IT Job Description</a></li><li class="chapter-item expanded "><a href="blog-rsync-net.html"><strong aria-hidden="true">19.6.</strong> Immutable Off-site Backups are Imperative</a></li><li class="chapter-item expanded "><a href="blog-llm-ai-operations-automation.html"><strong aria-hidden="true">19.7.</strong> Operations AI LLM Automation in 2025</a></li><li class="chapter-item expanded "><a href="blog-incus-netbird-phoenixnap.html"><strong aria-hidden="true">19.8.</strong> Hybrid Cloud Strategy: Incus + Netbird + PhoenixNAP</a></li><li class="chapter-item expanded "><a href="blog-letter-ceo.html"><strong aria-hidden="true">19.9.</strong> Letter to the CEO</a></li><li class="chapter-item expanded "><a href="blog-cli-better.html"><strong aria-hidden="true">19.10.</strong> The CLI is better than...</a></li><li class="chapter-item expanded "><a href="blog-conversational-enterprise-computing.html"><strong aria-hidden="true">19.11.</strong> Why Conversational Enterprise Computing Matters</a></li><li class="chapter-item expanded "><a href="blog-work-instruction-sexy.html"><strong aria-hidden="true">19.12.</strong> Work Instructions Make your Organization Sexy</a></li><li class="chapter-item expanded "><a href="blog-live-markdown-world.html"><strong aria-hidden="true">19.13.</strong> We Live in a Markdown World</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<!-- add things here that will go above the body navigation -->
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title"></h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="chuck-stack-architecture"><a class="header" href="#chuck-stack-architecture">chuck-stack Architecture</a></h1>
<p>In the <a href="./introduction.html">introduction</a>, we state the chuck-stack is a collection of:</p>
<ol>
<li><a href="./stack-tools.html">well understood tools</a></li>
<li><a href="./best-practices.html">organization best practices</a></li>
<li><a href="./stack-application.html">application framework</a></li>
</ol>
<p>The purpose of this page is to help you understand how the these tools fit together in deployment and usage. If you want to see the architecture in action, view the <a href="./picture-success.html#how-is-this-possible">picture of success</a>.</p>
<p>The chuck-stack architecture is designed around an organization only hiring two talents in its IT department:</p>
<ol>
<li>Linux</li>
<li>PostgreSQL</li>
</ol>
<p>Both talents will become proficient in AI in their respective disciplines. Both talents are optimized to help <a href="./terminology.html#superclerk">superclerks</a> automate their own roles (self-help).</p>
<h2 id="toc"><a class="header" href="#toc">TOC</a></h2>
<ul>
<li><a href="#configuration-over-code">Configuration Over Code</a>
<ul>
<li><a href="#nixos">NixOS</a></li>
<li><a href="#nix-shell">nix-shell</a></li>
<li><a href="#postgresql">PostgreSQL</a></li>
<li><a href="#work-instructions">Work Instructions</a></li>
</ul>
</li>
<li><a href="#user-experience">User Experience</a></li>
<li><a href="#administration-experience">Administration Experience</a></li>
<li><a href="#stk-application-example">Stk Application Example</a>
<ul>
<li><a href="#two-configurations">Two Configurations</a></li>
<li><a href="#assumptions">Assumptions</a></li>
<li><a href="#sql-migration">SQL Migration</a></li>
<li><a href="#nix-configuration-review">Nix Configuration Review</a></li>
</ul>
</li>
<li><a href="#all-in-one-server">All-In-One Server</a>
<ul>
<li><a href="#why-consider-an-all-in-one">Why Consider an All-In-One</a></li>
<li><a href="#all-in-one-architecture">All-In-One Architecture</a></li>
</ul>
</li>
</ul>
<h2 id="configuration-over-code"><a class="header" href="#configuration-over-code">Configuration Over Code</a></h2>
<p>One common theme you will find throughout the chuck-stack is the desire for configuration over code. This is true for both Linux and PostgreSQL. Inspecting the chuck-stack deployment highlights the extent of configuration. What little code that does exist comes in the form of high-value, human-readable work instructions and SQL DDL.</p>
<p>Actions to deploy the chuck-stack:</p>
<ul>
<li>System configuration (NixOS)</li>
<li>Role configuration (nix-shell)</li>
<li>PostgreSQL configuration (SQL DDL)</li>
<li>Work Instructions (plain text)</li>
</ul>
<h3 id="nixos"><a class="header" href="#nixos">NixOS</a></h3>
<p>Before we discuss NixOS, you should know a little about the <a href="./tool-linux.html#nix">Nix package management</a> tool.</p>
<p>The chuck-stack uses NixOS to deploy server applications because of its ability to simply describe the tools and configuration needed. Nix takes care of the deployment for us. This concept is true the day we deploy and anytime we perform maintenance thereafter. You simply declare what you want, and Nix makes that configuration come into existence.</p>
<p>Here are the <a href="https://github.com/chuckstack/chuck-stack-nixos/tree/main/nixos">chuck-stack NixOS repository configurations</a>.</p>
<p>Below is a diagram illustrating how you can simply add a NixOS configuration file to a server to create and configure important services.</p>
<p>diagram: nixos TODO</p>
<h3 id="nix-shell"><a class="header" href="#nix-shell">nix-shell</a></h3>
<p>The chuck-stack uses nix-shell to apply the proper role tools and configuration to the right users. Said another way, when a user connects to the chuck-stack, nix-shell applies all assigned roles and ensures the environment is configured so that the user can fulfill the role's duties.</p>
<p>Just like NixOS, nix-shell is configuration based. <!--TODO: need a better example that focuses on a role--></p>
<p>Here is a diagram showing how we use nix-shell.</p>
<p>diagram: nix-shell TODO</p>
<p>It is worth noting that both chuck-stack users and developers use nix-shell to perform their respective roles. While these role's tasks and tools may differ, we deliver the role work instructions and tools in the exact same way to all roles. This is an important point, and it differentiates the chuck-stack from its historical alternatives.</p>
<p>Here is an example of how a developer can use nix-shell to <a href="https://github.com/chuckstack/chuck-stack-core/blob/main/test/shell.nix">test a SQL migration</a> in a matter of seconds.</p>
<h3 id="postgresql"><a class="header" href="#postgresql">PostgreSQL</a></h3>
<p>The chuck-stack uses <a href="./tool-postgresql.html">PostgreSQL</a> to manage data, users, roles, records, workflows, attributes, documents, and more...</p>
<p>SQL is one of the most expressive and well-known data and data-access standards in the world. The chuck-stack creates simplicity by moving almost all application configuration and logic into the database, and using PostgreSQL where it excels the most. We challenge you to find a more popular, better documented, more capable, and more secure user/role system (other than Linux itself).</p>
<p>The chuck-stack uses the tight integration between Linux (NixOS), PostgreSQL and Git to describe application deployment and operation. The below <a href="#administration-experience">Administration Experience</a> sections highlights a common workflow using these tools.</p>
<p>By maximizing the features that make PostgreSQL great, we minimize the skills (and thereby experts) needed to make changes to your organization's system. You can find more information about <a href="./success-postgresql.html">how we use PostgreSQL here</a>. If you want a lot more information, see the <a href="./postgres-conventions.html">PostgreSQL Conventions</a> page.</p>
<p>Diagram: TODO</p>
<h3 id="work-instructions"><a class="header" href="#work-instructions">Work Instructions</a></h3>
<p>Described well <a href="./best-practices-operation-say.html">here</a>.</p>
<h2 id="user-experience"><a class="header" href="#user-experience">User Experience</a></h2>
<p>The majority of a user's experience is spent instructing the system via text or voice on what to do (much like with ChatGPT or Claude AI).</p>
<ul>
<li>Users connect via ssh into a remote session from any device (phone, tablet, laptop, or computer)</li>
<li>The remote session is configured by a nix-shell</li>
<li>The nix-shell launches <a href="./tool-zellij.html">Zellij</a> with one of a couple custom layouts</li>
<li>Users spend most of their time either interacting with the command line or AIChat's REPL</li>
<li>Users will typically create automation to remove as many manual steps as is possible</li>
</ul>
<!-- TODO: determine how users deploy a timer/cron task -->
<!-- TODO: determine best option for new users in text documents -->
<!-- TODO: reconcile use of local tools like Obsidian -->
<p>The user's experience is dictated by nix-shell. When a user connects, the system loads the appropriate nix-shell and makes sure the user has the tools available to execute the tasks assigned to their role(s).</p>
<h2 id="administration-experience"><a class="header" href="#administration-experience">Administration Experience</a></h2>
<p><a href="./tool-git.html">Git</a> plays a big role in chuck-stack administration workflows. Here is a typical scenario:</p>
<ul>
<li>Administrator needs to make a change - example: add a new user</li>
<li>Administrator makes a change to user.nix and commits the change</li>
<li>System automatically sees and deploys the updated configuration</li>
</ul>
<p>The Git branching feature dictates what environments get updated. A change to the 'Test1' branch will deploy changes to the 'Test1' UAT environment. A change to the 'Prod' branch will update the 'Prod' environment.</p>
<p>The Git PR (pull request) feature plays a big role in organizations where changes need to be vetted and approved by both AI and/or humans.</p>
<h2 id="stk-application-example"><a class="header" href="#stk-application-example">Stk Application Example</a></h2>
<p>Let's review the <a href="https://github.com/chuckstack/chuck-stack-nixos/blob/main/nixos/stk-core.nix">stk-core.nix</a> example chuck-stack application configuration to better understand how the pieces come together. The stk-core.nix is an example of a simple yet usable chuck-stack application.</p>
<h3 id="two-configurations"><a class="header" href="#two-configurations">Two Configurations</a></h3>
<p>The stk-core has two configuration components:</p>
<ol>
<li><a href="https://github.com/chuckstack/chuck-stack-nixos/blob/main/nixos/stk-core.nix">stk-core.nix</a> - the nix configuration file</li>
<li><a href="https://github.com/chuckstack/chuck-stack-core">chuck-stack-core</a> - the database migrations repository</li>
</ol>
<p>The <a href="https://github.com/chuckstack/chuck-stack-nixos/blob/main/nixos/stk-core.nix">stk-core.nix</a> configuration file creates a service to automatically clone and deploy the <a href="https://github.com/chuckstack/chuck-stack-core">chuck-stack-core</a> database migrations every time the service is started.</p>
<p>We want to make sure you understand just how incredible this scenario is... You simply update a brand new NixOS configuration to point to a nix application file and the system will automatically install, configure and run your application. Not only during installation, but it will do this as you make changes throughout time. That is almost magical.</p>
<h3 id="assumptions"><a class="header" href="#assumptions">Assumptions</a></h3>
<p>This section assumes <a href="https://github.com/chuckstack/chuck-stack-nixos/blob/main/nixos/system.nix">system.nix</a> and <a href="https://github.com/chuckstack/chuck-stack-nixos/blob/main/nixos/postgresql.nix">postgresql.nix</a> are also deployed at the same time. Said another way, stk-core depends on these services. By separating the system and the postgresql nix configurations, the stk-core remains as simple and ease to understand as possible.</p>
<h3 id="sql-migration"><a class="header" href="#sql-migration">SQL Migration</a></h3>
<p>Since the SQL migration concept is easier to explain, let's start here first. Database migrations are held in a dedicated Git repository. The typical chuck-stack organization will make frequent additions to the SQL migration repository. The reasons to make additions to migrations include:</p>
<ul>
<li>Making a DDL change to either the private or api database schemas</li>
<li>Adding and removing a new user or role</li>
<li>Fixing an error in a SQL table</li>
<li>Anything related to SQL data that needs change control and a permanent record</li>
</ul>
<p>One might argue that the user.nix should be moved to the SQL migration repository at the time of deployment so that all user and role management changes are managed in the same repository. This change is under consideration.</p>
<h3 id="nix-configuration-review"><a class="header" href="#nix-configuration-review">Nix Configuration Review</a></h3>
<p>Here is a breakdown of the <a href="https://github.com/chuckstack/chuck-stack-nixos/blob/main/nixos/stk-core.nix">stk-core.nix</a> file. Before we get into the details, let's first start with the highlights. Here is what the stk-core.nix configuration does for you:</p>
<ul>
<li>Updates the PostgreSQL configuration to include the stk_db database</li>
<li>Creates a service to deploy database migrations</li>
<li>Creates the <a href="./tool-postgrest.html">PostgREST</a> user and service to expose an API in addition to the CLI</li>
</ul>
<p>The first line is standard in all chuck-stack nix files.</p>
<pre><code class="language-nix">{ config, lib, pkgs, modulesPath, ... }:
</code></pre>
<p>The 'let' block establishes variables and defaults to be used in the rest of the file.</p>
<pre><code class="language-nix"> ...
postgrestPort = 3000; # variable
postgresUser = "postgrest";
postgresDb = "stk_todo_db";
...
</code></pre>
<p>Included in the 'let' block is a bash script that will be deployed as a systemd service. We highlight this feature because we greatly appreciate the utility and simplicity of creating a simple bash service.</p>
<pre><code class="language-nix"> ...
run-migrations = pkgs.writeScriptBin "run-migrations" ''
#!${pkgs.bash}/bin/bash
set -e
# Set your database URL
export DATABASE_URL="postgres:///stk_todo_db"
# Set the Git repository URL and the local path where it should be cloned
REPO_URL="https://github.com/chuckstack/chuck-stack-core.git"
CLONE_PATH="/tmp/db-migrations"
# Ensure the clone directory is empty
rm -rf "$CLONE_PATH"
# Clone the repository
${pkgs.git}/bin/git clone "$REPO_URL" "$CLONE_PATH"
# Change to the cloned directory
cd "$CLONE_PATH"
# Run the migrations
${pkgs.sqlx-cli}/bin/sqlx migrate run
# Clean up
cd /
rm -rf "$CLONE_PATH"
'';
...
</code></pre>
<h2 id="all-in-one-server"><a class="header" href="#all-in-one-server">All-In-One Server</a></h2>
<p>An all-in-one server describes a deployment scenario were all tools are deployed on a single virtualized server.</p>
<h3 id="why-consider-an-all-in-one"><a class="header" href="#why-consider-an-all-in-one">Why Consider an All-In-One</a></h3>
<p>Here are the benefits of an all-in-one deployment option:</p>
<ul>
<li>Least expensive</li>
<li>Simplest architecture</li>
<li>Most secure</li>
<li>Easiest to maintain a production environment</li>
<li>Easiest to create test environments</li>
</ul>
<h3 id="all-in-one-architecture"><a class="header" href="#all-in-one-architecture">All-In-One Architecture</a></h3>
<p>The following describes a typical all-in-one deployment:</p>
<ul>
<li>A single virtualized server running NixOS - note this server can run anywhere in the world</li>
<li>Configuration options/files are added to /etc/nixos/configuration.nix</li>
<li>postgresql.nix configures PostgreSQL to hold most if not all transactional details</li>
<li>user.nix maintains all users</li>
<li>Users ssh to this server to gain access to tools and data</li>
</ul>
<p>Here is a drawing representing a typical all-in-one:</p>
<p><img src="img/all-in-one-chuck-stack.svg" alt="all-in-one" /></p>
<br>
<p>Copyright © 2024-<script>document.write(new Date().getFullYear())</script>, CHUBOE LLC. All rights reserved.</p> <!--chuboe changed-->
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="tool-others.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="stack-application.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="tool-others.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="stack-application.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>