@regardio/dev 1.24.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/bin/ship/hotfix.bin.mjs +140 -0
- package/dist/bin/ship/production.bin.mjs +120 -0
- package/dist/bin/ship/staging.bin.mjs +70 -0
- package/dist/bin/ship/utils-BQ-JZ2D5.mjs +45 -0
- package/dist/playwright/index.d.mts +24 -0
- package/dist/playwright/index.mjs +61 -0
- package/dist/vitest/node.d.mts +22 -0
- package/dist/vitest/node.mjs +28 -0
- package/dist/vitest/react.d.mts +22 -0
- package/dist/vitest/react.mjs +28 -0
- package/docs/en/README.md +95 -0
- package/docs/en/agents.md +57 -0
- package/docs/en/standards/api.md +324 -0
- package/docs/en/standards/coding.md +144 -0
- package/docs/en/standards/commits.md +111 -0
- package/docs/en/standards/documentation.md +173 -0
- package/docs/en/standards/naming.md +180 -0
- package/docs/en/standards/principles.md +84 -0
- package/docs/en/standards/react.md +246 -0
- package/docs/en/standards/sql.md +258 -0
- package/docs/en/standards/testing.md +139 -0
- package/docs/en/standards/writing.md +119 -0
- package/docs/en/tools/biome.md +89 -0
- package/docs/en/tools/commitlint.md +92 -0
- package/docs/en/tools/dependencies.md +116 -0
- package/docs/en/tools/husky.md +90 -0
- package/docs/en/tools/markdownlint.md +84 -0
- package/docs/en/tools/playwright.md +117 -0
- package/docs/en/tools/releases.md +242 -0
- package/docs/en/tools/typescript.md +89 -0
- package/docs/en/tools/vitest.md +146 -0
- package/package.json +57 -70
- package/src/biome/preset.json +3 -0
- package/templates/changeset/README.md +14 -0
- package/templates/changeset/config.json +11 -0
- package/templates/github/release.yml +77 -0
- package/dist/bin/exec/clean.d.ts +0 -3
- package/dist/bin/exec/clean.d.ts.map +0 -1
- package/dist/bin/exec/clean.js +0 -25
- package/dist/bin/exec/clean.test.d.ts +0 -2
- package/dist/bin/exec/clean.test.d.ts.map +0 -1
- package/dist/bin/exec/clean.test.js +0 -45
- package/dist/bin/exec/husky.d.ts +0 -3
- package/dist/bin/exec/husky.d.ts.map +0 -1
- package/dist/bin/exec/husky.js +0 -9
- package/dist/bin/exec/p.d.ts +0 -3
- package/dist/bin/exec/p.d.ts.map +0 -1
- package/dist/bin/exec/p.js +0 -8
- package/dist/bin/exec/s.d.ts +0 -3
- package/dist/bin/exec/s.d.ts.map +0 -1
- package/dist/bin/exec/s.js +0 -8
- package/dist/bin/exec/tsc.d.ts +0 -3
- package/dist/bin/exec/tsc.d.ts.map +0 -1
- package/dist/bin/exec/tsc.js +0 -8
- package/dist/bin/lint/biome.d.ts +0 -3
- package/dist/bin/lint/biome.d.ts.map +0 -1
- package/dist/bin/lint/biome.js +0 -8
- package/dist/bin/lint/commit.d.ts +0 -3
- package/dist/bin/lint/commit.d.ts.map +0 -1
- package/dist/bin/lint/commit.js +0 -8
- package/dist/bin/lint/md.d.ts +0 -3
- package/dist/bin/lint/md.d.ts.map +0 -1
- package/dist/bin/lint/md.js +0 -16
- package/dist/bin/lint/package.d.ts +0 -4
- package/dist/bin/lint/package.d.ts.map +0 -1
- package/dist/bin/lint/package.js +0 -81
- package/dist/bin/lint/package.test.d.ts +0 -2
- package/dist/bin/lint/package.test.d.ts.map +0 -1
- package/dist/bin/lint/package.test.js +0 -65
- package/dist/bin/ship/hotfix.d.ts +0 -3
- package/dist/bin/ship/hotfix.d.ts.map +0 -1
- package/dist/bin/ship/hotfix.js +0 -141
- package/dist/bin/ship/production.d.ts +0 -3
- package/dist/bin/ship/production.d.ts.map +0 -1
- package/dist/bin/ship/production.js +0 -124
- package/dist/bin/ship/staging.d.ts +0 -3
- package/dist/bin/ship/staging.d.ts.map +0 -1
- package/dist/bin/ship/staging.js +0 -51
- package/dist/bin/ship/utils.d.ts +0 -9
- package/dist/bin/ship/utils.d.ts.map +0 -1
- package/dist/bin/ship/utils.js +0 -63
- package/dist/bin/ship/utils.test.d.ts +0 -2
- package/dist/bin/ship/utils.test.d.ts.map +0 -1
- package/dist/bin/ship/utils.test.js +0 -127
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/config.test.js +0 -101
- package/dist/playwright/index.d.ts +0 -10
- package/dist/playwright/index.d.ts.map +0 -1
- package/dist/playwright/index.js +0 -42
- package/dist/playwright/index.test.d.ts +0 -2
- package/dist/playwright/index.test.d.ts.map +0 -1
- package/dist/playwright/index.test.js +0 -55
- package/dist/testing/setup-react.d.ts +0 -2
- package/dist/testing/setup-react.d.ts.map +0 -1
- package/dist/testing/setup-react.js +0 -1
- package/dist/vitest/node.d.ts +0 -22
- package/dist/vitest/node.d.ts.map +0 -1
- package/dist/vitest/node.js +0 -16
- package/dist/vitest/react.d.ts +0 -17
- package/dist/vitest/react.d.ts.map +0 -1
- package/dist/vitest/react.js +0 -12
- package/src/bin/exec/clean.test.ts +0 -63
- package/src/bin/exec/clean.ts +0 -36
- package/src/bin/exec/husky.ts +0 -14
- package/src/bin/exec/p.ts +0 -13
- package/src/bin/exec/s.ts +0 -13
- package/src/bin/exec/tsc.ts +0 -13
- package/src/bin/lint/biome.ts +0 -13
- package/src/bin/lint/commit.ts +0 -13
- package/src/bin/lint/md.ts +0 -28
- package/src/bin/lint/package.test.ts +0 -83
- package/src/bin/lint/package.ts +0 -108
- package/src/bin/ship/hotfix.ts +0 -241
- package/src/bin/ship/production.ts +0 -240
- package/src/bin/ship/staging.ts +0 -108
- package/src/bin/ship/utils.test.ts +0 -178
- package/src/bin/ship/utils.ts +0 -109
- package/src/config.test.ts +0 -129
- package/src/markdownlint/markdownlint-cli2.jsonc +0 -9
- package/src/playwright/index.test.ts +0 -73
- package/src/playwright/index.ts +0 -63
- package/src/templates/release.yml +0 -128
- package/src/testing/setup-react.ts +0 -8
- package/src/vitest/node.ts +0 -25
- package/src/vitest/react.ts +0 -19
- /package/{src → templates}/sqlfluff/setup.cfg +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
title: "Documentation Standard"
|
|
4
|
+
description: "How Regardio documents its work — for agents to navigate, for humans to reason with, for tests to build on."
|
|
5
|
+
publishedAt: 2026-04-17
|
|
6
|
+
order: 1
|
|
7
|
+
language: "en"
|
|
8
|
+
status: "published"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
|
|
13
|
+
Regardio documentation is read by three audiences at once. Agents use it to answer questions about the system and to write code against a known contract. Humans use it to build a judgement of their own about what the project does and why. Tests use it as the specification the implementation is measured against.
|
|
14
|
+
|
|
15
|
+
Those audiences do not all need the same shape on every page. An architectural decision reads best as a short chain of reasoning — context, alternatives, what was chosen and why. A naming reference reads best as a catalogue. A quick introduction to a tool reads best as a few paragraphs and a short example. Forcing every document into one template serves the template rather than the content, and what the reader comes away with is ceremony instead of understanding.
|
|
16
|
+
|
|
17
|
+
What the documentation needs is enough predictability for tooling to rely on — a consistent frontmatter, a recognisable title, a place to find related reading — and enough freedom for each document to take the shape its content asks for.
|
|
18
|
+
|
|
19
|
+
## Decision
|
|
20
|
+
|
|
21
|
+
Every Regardio document carries a small shared surface. Underneath, it takes whichever of a few shapes fits the content it carries.
|
|
22
|
+
|
|
23
|
+
### Shared surface
|
|
24
|
+
|
|
25
|
+
Every document has the same top:
|
|
26
|
+
|
|
27
|
+
- **Frontmatter** that identifies the document and lets tooling index it
|
|
28
|
+
- **A title** as a heading or implicit from frontmatter
|
|
29
|
+
- **An opening that names what the document is for** — one or two sentences, before any sub-headings, so that a reader landing cold knows where they are
|
|
30
|
+
|
|
31
|
+
Every document has the same bottom:
|
|
32
|
+
|
|
33
|
+
- **Cross-references** to documents the reader is likely to want next, either inline in the prose or collected under `## Related` at the end
|
|
34
|
+
|
|
35
|
+
Between the top and the bottom, the document takes the shape its content asks for.
|
|
36
|
+
|
|
37
|
+
### Shapes the body takes
|
|
38
|
+
|
|
39
|
+
A few shapes recur. Pick the one the content fits; do not pad the content into a shape it resists.
|
|
40
|
+
|
|
41
|
+
**Decision record.** When the document captures a choice with real trade-offs, the ADR shape carries the reasoning well: *Status → Context → Decision → Alternatives Considered → Operational Rules → Consequences*. Operational Rules are the part tests bind to. The shape is an option for decision-heavy documents, not a requirement for every document.
|
|
42
|
+
|
|
43
|
+
**Reference catalogue.** When the content is a set of rules, names, or mappings that readers look up rather than read end-to-end, a catalogue of short sections with examples is the honest form. Naming conventions, file-layout rules, linter settings, and configuration tables read this way.
|
|
44
|
+
|
|
45
|
+
**Concept or entity note.** When the document describes a thing in the domain — a Channel, a Piece, a Plan — a short run of paragraphs that names the thing, its role, and its relations is usually enough. Two or three headings if the thing has parts worth naming separately.
|
|
46
|
+
|
|
47
|
+
**Quick introduction.** When the document introduces a tool or a workflow, a few paragraphs and a small example are enough. The reader needs to know what the thing is, when to reach for it, and where to go next. No ADR skeleton is required for a tool page.
|
|
48
|
+
|
|
49
|
+
**Warm reasoning.** When the document is working something out — a use case, a walkthrough, an explanation of why a piece of the domain behaves the way it does — prose that follows the thought is the right form. Headings appear where they help the reader keep their place, not because structure is owed.
|
|
50
|
+
|
|
51
|
+
A document can borrow from more than one shape. An architectural document might open with warm reasoning and close with Operational Rules. An entity note might include a short alternatives paragraph when the entity's shape had genuine contenders. The shapes are orientation, not slots.
|
|
52
|
+
|
|
53
|
+
### Frontmatter
|
|
54
|
+
|
|
55
|
+
Frontmatter is the part tooling reads. Keep it stable.
|
|
56
|
+
|
|
57
|
+
| Field | Required | Notes |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `title` | yes | Noun phrase naming the document. Decision records may prefix `"ADR: "`. |
|
|
60
|
+
| `description` | yes | One sentence. What this document is for, without hedging. |
|
|
61
|
+
| `publishedAt` | yes | ISO date (`YYYY-MM-DD`) the document was first accepted. |
|
|
62
|
+
| `status` | yes | `"draft"`, `"published"`, `"superseded"`. |
|
|
63
|
+
| `language` | yes | `"en"`, `"de"`. |
|
|
64
|
+
| `order` | no | Integer, when a sibling set has a meaningful reading order. |
|
|
65
|
+
| `kind` | no | `"adr"`, `"entity"`, `"concept"`, `"architecture"`, `"guide"`, `"use-case"`, `"reference"`. Lets agents and renderers pick the right treatment. |
|
|
66
|
+
| `area` | no | `"ensemble"`, `"supabase"`, `"connect"`, `"instrument"`, `"dev"`. Names the implementation the document belongs to. |
|
|
67
|
+
| `supersedes` | no | Filename (without extension) of the document this one replaces. |
|
|
68
|
+
| `supersededBy` | no | Filename of the document that replaced this one. |
|
|
69
|
+
|
|
70
|
+
### Tense and stance
|
|
71
|
+
|
|
72
|
+
Documents describe what the system does, in the present tense, observed rather than advertised. "The publication function returns pieces ordered by `sort_order`." Not "The publication function will return…" and not "We should implement…". The tense holds whether the behaviour is currently built or still being specified; the `status` frontmatter carries the difference.
|
|
73
|
+
|
|
74
|
+
The stance is observational. A Regardio document is not a pitch. It notices how the system fits together and what follows from that. Reliability, safety, transparency, usefulness, and care for the people the software serves show up through how the reasoning is laid out, not by being claimed. A reader who finishes a document should be able to make their own judgement about whether the system is sound — that is what the prose is for.
|
|
75
|
+
|
|
76
|
+
### What shows up where
|
|
77
|
+
|
|
78
|
+
- **Code snippets** appear where they clarify a contract, a data shape, or a naming pattern. Reference catalogues quite properly carry several; decision records rarely need any. A snippet never stands in for the reasoning around it.
|
|
79
|
+
- **Names** (files, functions, columns, handles) appear where they are contracts readers rely on. They do not appear as a substitute for describing what something does.
|
|
80
|
+
- **Procedural steps** belong in runbooks and READMEs. A domain spec does not read like a cookbook.
|
|
81
|
+
|
|
82
|
+
### Cross-references
|
|
83
|
+
|
|
84
|
+
Links carry a short descriptor of what the link leads to, not just a filename:
|
|
85
|
+
|
|
86
|
+
```markdown
|
|
87
|
+
The [Channel](../entities/channel.md) is the publication destination;
|
|
88
|
+
the [Publishing Architecture](../architecture/publishing-architecture.md)
|
|
89
|
+
describes how callers reach it.
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`## Related` at the end of a document lists the next pages a reader is likely to want.
|
|
93
|
+
|
|
94
|
+
### Voice
|
|
95
|
+
|
|
96
|
+
The [Writing](./writing.md) standard covers voice, tone, and language. This document relies on it rather than repeating it.
|
|
97
|
+
|
|
98
|
+
## Alternatives Considered
|
|
99
|
+
|
|
100
|
+
### A single ADR skeleton for every document
|
|
101
|
+
|
|
102
|
+
**Dismissed because** it presses reference catalogues and tool introductions into a shape that does not suit them. The skeleton adds ceremony where the content is already clear, and readers learn to skim past sections that carry no weight. The skeleton remains available for documents whose content earns it.
|
|
103
|
+
|
|
104
|
+
### No shared shape at all
|
|
105
|
+
|
|
106
|
+
**Dismissed because** agents and tooling need something predictable to index against, and readers benefit from landing on any document and knowing roughly where to look. A thin shared surface — frontmatter, opening line, closing references — is enough.
|
|
107
|
+
|
|
108
|
+
### Separate templates per document kind
|
|
109
|
+
|
|
110
|
+
**Dismissed because** the kinds blur at the edges. An entity note sometimes carries a decision; a use case sometimes carries a catalogue. A small set of recognisable shapes that documents can borrow from works better than a closed list of templates.
|
|
111
|
+
|
|
112
|
+
## Operational Rules
|
|
113
|
+
|
|
114
|
+
### Frontmatter is complete
|
|
115
|
+
|
|
116
|
+
Every document carries `title`, `description`, `publishedAt`, `status`, and `language`. Tooling that indexes or lists documents relies on these five.
|
|
117
|
+
|
|
118
|
+
### Opening names the subject
|
|
119
|
+
|
|
120
|
+
Before the first sub-heading, a reader can tell what the document is for. If the opening does not make this clear, the document is not ready.
|
|
121
|
+
|
|
122
|
+
### Shape follows content
|
|
123
|
+
|
|
124
|
+
The body takes the shape the content asks for. A decision record uses the ADR skeleton if that skeleton helps the reasoning; a reference uses a catalogue; an introduction stays short. Where a document borrows from more than one shape, it does so in service of the reader, not in service of the template.
|
|
125
|
+
|
|
126
|
+
### Tense is present, stance is observational
|
|
127
|
+
|
|
128
|
+
Documents describe the system as it is, in the present tense. Not-yet-built behaviour is flagged through `status`, not through hedged tense. The prose observes rather than promotes.
|
|
129
|
+
|
|
130
|
+
### Reasoning is preserved, not rewritten
|
|
131
|
+
|
|
132
|
+
When a decision is revisited, the existing document is superseded. The old reasoning stays readable so that future readers can see what was known at the time. An in-place rewrite that changes direction without supersession loses the history.
|
|
133
|
+
|
|
134
|
+
### Code and names earn their place
|
|
135
|
+
|
|
136
|
+
A snippet appears because it clarifies a contract the prose cannot carry alone. A specific name appears because callers rely on it. Both are tools for the reader, not decoration.
|
|
137
|
+
|
|
138
|
+
### Tests can point at a document
|
|
139
|
+
|
|
140
|
+
A behaviour worth testing has a place in a document that names it. The document does not need a section labelled "Operational Rules" for this — it needs prose clear enough that a test can quote it and both the test author and the reviewer know what is being verified.
|
|
141
|
+
|
|
142
|
+
### One subject per document
|
|
143
|
+
|
|
144
|
+
A document names one entity, one concept, one decision, one scenario. When a draft sprawls across several, the move is to split it.
|
|
145
|
+
|
|
146
|
+
## Consequences
|
|
147
|
+
|
|
148
|
+
### Positive
|
|
149
|
+
|
|
150
|
+
- Documents read naturally for their content. ADRs feel like ADRs; reference catalogues feel like reference catalogues; introductions stay short.
|
|
151
|
+
- Agents and humans find a predictable frontmatter and opening, and the body of each document carries its reasoning in the form that fits.
|
|
152
|
+
- The docs stay honest. Observational prose about what the system does leaves room for the reader to form a judgement, rather than prescribing one.
|
|
153
|
+
- Tests bind to the prose that describes behaviour, wherever in the document that prose lives.
|
|
154
|
+
|
|
155
|
+
### Negative
|
|
156
|
+
|
|
157
|
+
- "Shape follows content" asks for judgement. Contributors unsure of the right shape need a reference document to look at; the existing documents serve that role.
|
|
158
|
+
- Without a single template, reviewers sometimes have to say "this would read better as a catalogue" or "this would read better as an ADR". That conversation is part of the standard, not a cost around it.
|
|
159
|
+
|
|
160
|
+
### Mitigations
|
|
161
|
+
|
|
162
|
+
- New documents are often patterned on a nearby existing one. A contributor writing a new entity note copies the shape of an adjacent entity note; a contributor writing an ADR copies an adjacent ADR.
|
|
163
|
+
- Reviewers point at this document when a draft has picked a shape that resists its content, and help the author find the form the content already has.
|
|
164
|
+
|
|
165
|
+
## Related
|
|
166
|
+
|
|
167
|
+
- [Writing](./writing.md) — Voice, tone, language
|
|
168
|
+
- [AI Agent Guidelines](../agents.md) — How agents use these documents
|
|
169
|
+
- [Principles](./principles.md) — Shared development principles
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
**License**: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) © Regardio
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
title: "Naming"
|
|
4
|
+
description: "Naming patterns across TypeScript, SQL, CSS, Git, and configuration — each language in its own idiom, aligned across the seams."
|
|
5
|
+
publishedAt: 2026-04-17
|
|
6
|
+
order: 4
|
|
7
|
+
language: "en"
|
|
8
|
+
status: "published"
|
|
9
|
+
kind: "reference"
|
|
10
|
+
area: "dev"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
A name is the shortest documentation a thing gets. The same concept can appear in TypeScript, a SQL column, a CSS class, and a branch; when the words line up across those surfaces, the concept stays recognisable. The convention is to match each language's native idiom and keep the words in the same order across languages.
|
|
14
|
+
|
|
15
|
+
## General
|
|
16
|
+
|
|
17
|
+
- Names carry their purpose — `getUserById` not `getUsrByID`
|
|
18
|
+
- Consistent patterns within each language
|
|
19
|
+
- Abbreviations only when they are genuinely universal (`id`, `url`, `http`)
|
|
20
|
+
- Domain language where domain words exist
|
|
21
|
+
|
|
22
|
+
## TypeScript and JavaScript
|
|
23
|
+
|
|
24
|
+
### Variables and functions
|
|
25
|
+
|
|
26
|
+
`camelCase`:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
const userName = 'alice';
|
|
30
|
+
function calculateTotal(items: Item[]): number { }
|
|
31
|
+
async function fetchUserProfile(userId: string): Promise<User> { }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Types, interfaces, classes
|
|
35
|
+
|
|
36
|
+
`PascalCase`:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
interface UserProfile { id: string; displayName: string; createdAt: Date; }
|
|
40
|
+
type RequestStatus = 'pending' | 'success' | 'error';
|
|
41
|
+
class PaymentProcessor { }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Constants
|
|
45
|
+
|
|
46
|
+
`UPPER_SNAKE_CASE`:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const MAX_RETRY_ATTEMPTS = 3;
|
|
50
|
+
const API_BASE_URL = 'https://api.example.com';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### React components
|
|
54
|
+
|
|
55
|
+
`PascalCase` for components, `camelCase` for props:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
interface ButtonProps { variant: 'primary' | 'secondary'; onClick: () => void; }
|
|
59
|
+
function ActionButton({ variant, onClick }: ButtonProps) { }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Files and directories
|
|
63
|
+
|
|
64
|
+
- Lowercase `kebab-case`
|
|
65
|
+
- Tests end in `.test.ts`
|
|
66
|
+
- File names match the concept they export
|
|
67
|
+
|
|
68
|
+
## SQL
|
|
69
|
+
|
|
70
|
+
### Tables and columns
|
|
71
|
+
|
|
72
|
+
`snake_case`, tables in the singular:
|
|
73
|
+
|
|
74
|
+
```sql
|
|
75
|
+
create table member (
|
|
76
|
+
id uuid primary key,
|
|
77
|
+
display_name text not null,
|
|
78
|
+
created_at timestamptz default now()
|
|
79
|
+
);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Column suffixes:
|
|
83
|
+
|
|
84
|
+
- `id` — primary key
|
|
85
|
+
- `{referenced_table}_id` — foreign key
|
|
86
|
+
- `{field}_intl` — internationalised text (`jsonb`, keys are locale codes)
|
|
87
|
+
- `{event}_at` — timestamps
|
|
88
|
+
- `deleted_at` — soft-delete marker
|
|
89
|
+
|
|
90
|
+
### Functions
|
|
91
|
+
|
|
92
|
+
Pattern: `{domain}_{verb}` or `{domain}_{verb}_{target}`
|
|
93
|
+
|
|
94
|
+
```sql
|
|
95
|
+
create function util_generate_slug(_input text) ...
|
|
96
|
+
create function task_get_status(_task_id uuid) ...
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Standard verbs: `get`, `list`, `create`, `update`, `delete`, `check`, `is`, `has`, `set`, `generate`.
|
|
100
|
+
|
|
101
|
+
### Parameters and variables
|
|
102
|
+
|
|
103
|
+
Prefix `_` for parameters, `v_` for local variables:
|
|
104
|
+
|
|
105
|
+
```sql
|
|
106
|
+
create function process_order(_order_id uuid)
|
|
107
|
+
returns void
|
|
108
|
+
language plpgsql
|
|
109
|
+
as $func$
|
|
110
|
+
declare
|
|
111
|
+
v_total numeric;
|
|
112
|
+
begin
|
|
113
|
+
-- body
|
|
114
|
+
end;
|
|
115
|
+
$func$;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Objects bound to a table
|
|
119
|
+
|
|
120
|
+
- Check constraints — `chk_{table}_{field}_{purpose}`
|
|
121
|
+
- Unique constraints — `uq_{table}_{field}`
|
|
122
|
+
- Indexes — `idx_{table}_{field}`; unique as `idx_unique_{table}_{field}`
|
|
123
|
+
- Triggers — `trg_{table}_{purpose}`
|
|
124
|
+
- RLS policies — `pol_{table}_{operation}`
|
|
125
|
+
|
|
126
|
+
## CSS
|
|
127
|
+
|
|
128
|
+
`kebab-case`; BEM-style modifiers where useful:
|
|
129
|
+
|
|
130
|
+
```css
|
|
131
|
+
.user-profile { }
|
|
132
|
+
.action-button--primary { }
|
|
133
|
+
|
|
134
|
+
:root {
|
|
135
|
+
--color-primary: #007bff;
|
|
136
|
+
--spacing-md: 1rem;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Git
|
|
141
|
+
|
|
142
|
+
### Branches
|
|
143
|
+
|
|
144
|
+
`kebab-case` with a type prefix:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
feature/user-authentication
|
|
148
|
+
fix/login-redirect-loop
|
|
149
|
+
docs/api-documentation
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Commit subjects
|
|
153
|
+
|
|
154
|
+
Conventional Commits, imperative mood — see [Commits](./commits.md).
|
|
155
|
+
|
|
156
|
+
## Configuration
|
|
157
|
+
|
|
158
|
+
- JSON / JSONC keys — `camelCase`
|
|
159
|
+
- Environment variables — `UPPER_SNAKE_CASE`
|
|
160
|
+
- Package names — scoped, `kebab-case` (`@regardio/react`, `@regardio/ensemble-supabase`)
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{ "compilerOptions": { "strictNullChecks": true } }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
DATABASE_URL=postgres://localhost:5432/mydb
|
|
168
|
+
NODE_ENV=production
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Related
|
|
172
|
+
|
|
173
|
+
- [Coding](./coding.md) — TypeScript and general patterns
|
|
174
|
+
- [SQL](./sql.md) — PostgreSQL naming, structure, and access
|
|
175
|
+
- [Commits](./commits.md) — Branch and commit naming
|
|
176
|
+
- [Writing](./writing.md) — Voice, tone, language
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
**License**: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) © Regardio
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
title: "Principles"
|
|
4
|
+
description: "The shared ground Regardio projects stand on — six clusters of principles that carry across languages and repos."
|
|
5
|
+
publishedAt: 2026-04-17
|
|
6
|
+
order: 3
|
|
7
|
+
language: "en"
|
|
8
|
+
status: "published"
|
|
9
|
+
kind: "reference"
|
|
10
|
+
area: "dev"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Regardio spans several codebases and several languages. What keeps them legible to each other is a short list of principles held in common — enough shared ground that a contributor moving between projects finds the same habits in force, and enough room left for each codebase to speak its own idiom.
|
|
14
|
+
|
|
15
|
+
Six clusters, a handful of items each.
|
|
16
|
+
|
|
17
|
+
## Code quality
|
|
18
|
+
|
|
19
|
+
- Readable code over clever code
|
|
20
|
+
- Consistent naming within each language — `camelCase` in TypeScript, `snake_case` in SQL
|
|
21
|
+
- Small functions with a single responsibility
|
|
22
|
+
- Explicit choices over implicit defaults
|
|
23
|
+
|
|
24
|
+
## Architecture
|
|
25
|
+
|
|
26
|
+
- Modules decouple from each other; dependencies are deliberate
|
|
27
|
+
- Duplication resolves into an abstraction only when the pattern is clear
|
|
28
|
+
- Interfaces describe what a module does, not how it does it
|
|
29
|
+
- Concerns separate along the seams the domain suggests
|
|
30
|
+
|
|
31
|
+
## Error handling
|
|
32
|
+
|
|
33
|
+
- Input is validated early; failures surface with a clear message
|
|
34
|
+
- Validation covers correctness and security in the same pass
|
|
35
|
+
- Logic stays separated from side effects so it remains testable
|
|
36
|
+
- Dependencies can fail; the code degrades gracefully when they do
|
|
37
|
+
|
|
38
|
+
## Performance
|
|
39
|
+
|
|
40
|
+
- Data structures match the shape of the work
|
|
41
|
+
- Measurement comes before optimisation
|
|
42
|
+
- Resources — memory, connections, file handles — are released on the path that acquired them
|
|
43
|
+
- Scale is considered at design time, not retrofitted
|
|
44
|
+
|
|
45
|
+
## Security
|
|
46
|
+
|
|
47
|
+
- Client data is untrusted by default; server-side validation is the line
|
|
48
|
+
- Privileges stay narrow; access is opened deliberately
|
|
49
|
+
- Defence is layered; a single check never stands alone
|
|
50
|
+
- Openness is an opt-in, not the default posture
|
|
51
|
+
|
|
52
|
+
## Maintainability
|
|
53
|
+
|
|
54
|
+
- Patterns repeat across the codebase so that reading one teaches reading the rest
|
|
55
|
+
- Commits are atomic and speak to one change at a time
|
|
56
|
+
- Refactoring is continuous; debt is paid down rather than accumulated
|
|
57
|
+
|
|
58
|
+
## Implementation workflow
|
|
59
|
+
|
|
60
|
+
Non-trivial work tends to follow this sequence — not as a ritual, but because skipping a step usually costs more later than it saves now:
|
|
61
|
+
|
|
62
|
+
1. **Understand the business logic first.** The deepest defects come from misunderstood requirements. Read the relevant domain document; know what is needed now rather than what might be needed later.
|
|
63
|
+
2. **Look for existing solutions.** Well-maintained libraries are evaluated before custom code is written. Dependencies are vetted for design quality, test coverage, and recent activity.
|
|
64
|
+
3. **Write the tests as specification.** The behaviour a change produces is described as tests before the change is written. Tests are the contract; the code is measured against them.
|
|
65
|
+
4. **Implement with reusability in mind, not reusability as the goal.** Duplicate until the pattern is clear, then extract. Wrong abstractions cost more than duplication.
|
|
66
|
+
5. **Stop and reconsider when complexity grows.** Difficulty that keeps growing despite good preparation is a signal. Back out, simplify, or question the approach.
|
|
67
|
+
6. **Document intent, not mechanics.** Comments explain *why*; the code explains *what*. Existing context is checked before new prose is added.
|
|
68
|
+
|
|
69
|
+
## Collaboration
|
|
70
|
+
|
|
71
|
+
- Every change passes through review
|
|
72
|
+
- Code quality is shared, not owned
|
|
73
|
+
- Decisions that involve a real trade-off leave a trace in the project's `docs/en` tree
|
|
74
|
+
|
|
75
|
+
## Related
|
|
76
|
+
|
|
77
|
+
- [Coding](./coding.md) — TypeScript and general patterns
|
|
78
|
+
- [Testing](./testing.md) — Testing philosophy
|
|
79
|
+
- [Documentation Standard](./documentation.md) — How documents are shaped
|
|
80
|
+
- [Writing](./writing.md) — Voice, tone, language
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
**License**: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) © Regardio
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
title: "React"
|
|
4
|
+
description: "Component, hook, state, and performance patterns the Regardio React apps hold to."
|
|
5
|
+
publishedAt: 2026-04-17
|
|
6
|
+
order: 6
|
|
7
|
+
language: "en"
|
|
8
|
+
status: "published"
|
|
9
|
+
kind: "reference"
|
|
10
|
+
area: "dev"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Regardio's user-facing surfaces — the Instrument app, the channel apps, the Storybook-hosted component packages — are all React. They share a design system through `@regardio/react` and styling through `@regardio/tailwind`. A contributor moving between them finds the same component shapes and the same decisions about where state lives. This page names those shared patterns.
|
|
14
|
+
|
|
15
|
+
## TypeScript in React
|
|
16
|
+
|
|
17
|
+
### Types
|
|
18
|
+
|
|
19
|
+
- Explicit types on function parameters and public return values
|
|
20
|
+
- `interface` for object shapes; `type` for unions
|
|
21
|
+
- Generic constraints when a type carries across boundaries
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
interface UserData {
|
|
25
|
+
id: string;
|
|
26
|
+
email: string;
|
|
27
|
+
displayName: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface Repository<T extends { id: string }> {
|
|
31
|
+
findById(id: string): Promise<T | null>;
|
|
32
|
+
create(data: Pick<T, Exclude<keyof T, 'id'>>): Promise<T>;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Naming
|
|
37
|
+
|
|
38
|
+
- `camelCase` — variables, functions, methods
|
|
39
|
+
- `PascalCase` — types, interfaces, classes, components
|
|
40
|
+
- `UPPER_SNAKE_CASE` — constants
|
|
41
|
+
|
|
42
|
+
### Error handling
|
|
43
|
+
|
|
44
|
+
Result types at API boundaries; specific error types for known failure modes:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
type Result<T, E = Error> =
|
|
48
|
+
| { success: true; data: T }
|
|
49
|
+
| { success: false; error: E };
|
|
50
|
+
|
|
51
|
+
async function fetchUser(id: string): Promise<Result<User>> {
|
|
52
|
+
try {
|
|
53
|
+
const data = await api.getUser(id);
|
|
54
|
+
return { success: true, data };
|
|
55
|
+
} catch (error) {
|
|
56
|
+
return { success: false, error: error as Error };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Components
|
|
62
|
+
|
|
63
|
+
### Structure
|
|
64
|
+
|
|
65
|
+
- Functional components with hooks
|
|
66
|
+
- One responsibility per component
|
|
67
|
+
- Composition over inheritance
|
|
68
|
+
- Explicit props interface
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
interface CardProps {
|
|
72
|
+
title: string;
|
|
73
|
+
description: string;
|
|
74
|
+
onSelect: (id: string) => void;
|
|
75
|
+
isSelected?: boolean;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function Card({ title, description, onSelect, isSelected = false }: CardProps) {
|
|
79
|
+
const handleClick = useCallback(() => onSelect(title), [title, onSelect]);
|
|
80
|
+
return (
|
|
81
|
+
<div className={cn('card', { selected: isSelected })} onClick={handleClick}>
|
|
82
|
+
<h3>{title}</h3>
|
|
83
|
+
<p>{description}</p>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Categories
|
|
90
|
+
|
|
91
|
+
- **UI components** — pure, reusable, no business logic
|
|
92
|
+
- **Feature components** — domain logic, backend integration
|
|
93
|
+
- **Page components** — route-level; compose features
|
|
94
|
+
|
|
95
|
+
### File layout
|
|
96
|
+
|
|
97
|
+
- `components/ui/` — reusable UI components
|
|
98
|
+
- `components/features/` — feature-specific components
|
|
99
|
+
- `hooks/` — custom hooks
|
|
100
|
+
- `types/` — shared types
|
|
101
|
+
- `utils/` — framework-agnostic helpers
|
|
102
|
+
|
|
103
|
+
### Props
|
|
104
|
+
|
|
105
|
+
- Pass only what the component uses
|
|
106
|
+
- `useCallback` for function props that cross memoised boundaries
|
|
107
|
+
- Sensible defaults; undefined handled gracefully
|
|
108
|
+
|
|
109
|
+
## Hooks
|
|
110
|
+
|
|
111
|
+
- Dependencies declared in full for `useEffect`, `useMemo`, `useCallback`
|
|
112
|
+
- Reusable logic extracts into a custom hook, name prefixed `use`
|
|
113
|
+
- Cleanup releases whatever the hook set up
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
function useWebSocket(url: string) {
|
|
117
|
+
const [data, setData] = useState<unknown>(null);
|
|
118
|
+
const [status, setStatus] = useState<'connecting' | 'connected' | 'disconnected'>('connecting');
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
const ws = new WebSocket(url);
|
|
122
|
+
ws.onopen = () => setStatus('connected');
|
|
123
|
+
ws.onmessage = (event) => setData(JSON.parse(event.data));
|
|
124
|
+
ws.onclose = () => setStatus('disconnected');
|
|
125
|
+
return () => ws.close();
|
|
126
|
+
}, [url]);
|
|
127
|
+
|
|
128
|
+
return { data, status };
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Event handling
|
|
133
|
+
|
|
134
|
+
- Typed with the React event they receive
|
|
135
|
+
- Forms prevent default and read values from controlled inputs
|
|
136
|
+
- Keyboard handlers accompany mouse handlers
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
function SearchForm({ onSubmit }: { onSubmit: (query: string) => void }) {
|
|
140
|
+
const [query, setQuery] = useState('');
|
|
141
|
+
|
|
142
|
+
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
143
|
+
e.preventDefault();
|
|
144
|
+
onSubmit(query);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<form onSubmit={handleSubmit}>
|
|
149
|
+
<input
|
|
150
|
+
value={query}
|
|
151
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
152
|
+
onKeyDown={(e) => e.key === 'Escape' && setQuery('')}
|
|
153
|
+
aria-label="Search"
|
|
154
|
+
/>
|
|
155
|
+
<button type="submit">Search</button>
|
|
156
|
+
</form>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## State
|
|
162
|
+
|
|
163
|
+
### Local
|
|
164
|
+
|
|
165
|
+
- `useState` for simple component state
|
|
166
|
+
- `useReducer` when the shape grows beyond two or three related pieces
|
|
167
|
+
- Custom hooks for reusable state logic
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
type State = { items: Item[]; filter: string; sortBy: 'name' | 'date'; loading: boolean };
|
|
171
|
+
type Action =
|
|
172
|
+
| { type: 'SET_ITEMS'; items: Item[] }
|
|
173
|
+
| { type: 'SET_FILTER'; filter: string }
|
|
174
|
+
| { type: 'SET_SORT'; sortBy: 'name' | 'date' }
|
|
175
|
+
| { type: 'SET_LOADING'; loading: boolean };
|
|
176
|
+
|
|
177
|
+
function reducer(state: State, action: Action): State {
|
|
178
|
+
switch (action.type) {
|
|
179
|
+
case 'SET_ITEMS': return { ...state, items: action.items };
|
|
180
|
+
case 'SET_FILTER': return { ...state, filter: action.filter };
|
|
181
|
+
case 'SET_SORT': return { ...state, sortBy: action.sortBy };
|
|
182
|
+
case 'SET_LOADING': return { ...state, loading: action.loading };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Global
|
|
188
|
+
|
|
189
|
+
- Context for theme, session, user preferences
|
|
190
|
+
- A dedicated store for application state that genuinely spans the app
|
|
191
|
+
- React Query (or equivalent) for server state
|
|
192
|
+
|
|
193
|
+
## Performance
|
|
194
|
+
|
|
195
|
+
- Code-split by route and feature; lazy-load what isn't needed yet
|
|
196
|
+
- `React.memo`, `useMemo`, `useCallback` where profiling points at a win — not as defensive decoration
|
|
197
|
+
- Bundle size monitored
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
const Dashboard = lazy(() => import('./pages/Dashboard'));
|
|
201
|
+
|
|
202
|
+
function App() {
|
|
203
|
+
return (
|
|
204
|
+
<Suspense fallback={<LoadingSpinner />}>
|
|
205
|
+
<Routes>
|
|
206
|
+
<Route path="/dashboard" element={<Dashboard />} />
|
|
207
|
+
</Routes>
|
|
208
|
+
</Suspense>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Testing
|
|
214
|
+
|
|
215
|
+
Components are tested through the interface a user reaches — roles, labels, visible text, keyboard. Implementation-detail assertions (internal state, render counts) do not appear.
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
describe('SearchForm', () => {
|
|
219
|
+
it('calls onSubmit with query when form is submitted', async () => {
|
|
220
|
+
const mockOnSubmit = vi.fn();
|
|
221
|
+
render(<SearchForm onSubmit={mockOnSubmit} />);
|
|
222
|
+
const input = screen.getByRole('textbox', { name: /search/i });
|
|
223
|
+
await user.type(input, 'test query');
|
|
224
|
+
await user.click(screen.getByRole('button', { name: /search/i }));
|
|
225
|
+
expect(mockOnSubmit).toHaveBeenCalledWith('test query');
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Accessibility
|
|
231
|
+
|
|
232
|
+
- Keyboard navigation verified
|
|
233
|
+
- Screen-reader access through roles and labels
|
|
234
|
+
- Focus management checked on interactive flows
|
|
235
|
+
- ARIA attributes correct where they carry meaning
|
|
236
|
+
|
|
237
|
+
## Related
|
|
238
|
+
|
|
239
|
+
- [Coding](./coding.md) — TypeScript patterns React code builds on
|
|
240
|
+
- [Testing](./testing.md) — Testing philosophy and layers
|
|
241
|
+
- [Principles](./principles.md) — Shared principles across the stack
|
|
242
|
+
- [Naming](./naming.md) — Names across languages
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
**License**: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) © Regardio
|