@arcforgelabs/flow 2026.10.23 → 2026.10.25
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 +1 -1
- package/VISION.md +56 -15
- package/npm-shrinkwrap.json +12 -2
- package/package.json +2 -1
- package/server/integrations/setup.js +1 -1
- package/server/theme/font-families.js +1 -0
- package/server/theme/themes.js +57 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Flow
|
|
2
2
|
|
|
3
|
-
Flow is invoicing, bill approval and a financial dashboard for labs that make
|
|
3
|
+
Flow is job management, invoicing, bill approval and a financial dashboard for labs that make
|
|
4
4
|
work to order, first for dental labs. Seazona (the lab's case system) is a
|
|
5
5
|
bundled integration, and Xero is an optional one. See `VISION.md`.
|
|
6
6
|
|
package/VISION.md
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
# Flow — Vision
|
|
2
2
|
|
|
3
|
-
Flow is invoicing, bill approval and a financial dashboard
|
|
4
|
-
makes work to order, first for dental labs. It is a complete
|
|
5
|
-
its own database. It is not a sync engine between other
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
Flow is job management, invoicing, bill approval and a financial dashboard
|
|
4
|
+
for a lab that makes work to order, first for dental labs. It is a complete
|
|
5
|
+
application with its own database. It is not a sync engine between other
|
|
6
|
+
products.
|
|
7
|
+
|
|
8
|
+
It is for the lab manager, the staff who move the work, and the person who
|
|
9
|
+
bills it and pays the suppliers. Finished feels like this: Flow opens on a
|
|
10
|
+
job board that shows every job by stage, with due dates and late jobs marked;
|
|
11
|
+
completed jobs become invoices they check and send; supplier bills are
|
|
12
|
+
reviewed and approved; and one dashboard shows cash, what is owed to the lab,
|
|
13
|
+
what the lab owes, and the GST for the BAS period. Every invoice a customer
|
|
14
|
+
was sent can be found again, exactly as it was sent.
|
|
12
15
|
|
|
13
16
|
Flow is open source so any lab can run its own installation.
|
|
14
17
|
|
|
15
18
|
## The core and its integrations
|
|
16
19
|
|
|
17
|
-
The core is invoices, bills, payments, credit notes,
|
|
18
|
-
the
|
|
20
|
+
The core is jobs and the job board, invoices, bills, payments, credit notes,
|
|
21
|
+
contacts, the price list, approvals and the dashboard. The core holds its own copy of
|
|
19
22
|
every record it shows, so it works with no integration connected and an owner
|
|
20
23
|
can build reports and features on its data.
|
|
21
24
|
|
|
@@ -33,6 +36,39 @@ data spine (`docs/DATA_SPINE.md`): its records come into a mirror, get a Flow
|
|
|
33
36
|
identity, and become core records; Flow's writes leave through an outbox; a
|
|
34
37
|
conflict goes to one review queue; one job queue runs the work.
|
|
35
38
|
|
|
39
|
+
## Job management
|
|
40
|
+
|
|
41
|
+
Flow links each job to its client and its invoice. That link is the heart
|
|
42
|
+
of the product: a job card shows what was ordered, who it is for, and how it
|
|
43
|
+
was billed and paid.
|
|
44
|
+
|
|
45
|
+
Flow does a few parts of job management well now, and more later. It does
|
|
46
|
+
not try to replace the lab's case system.
|
|
47
|
+
|
|
48
|
+
- **Now:** update job cards and process a job's information for invoicing,
|
|
49
|
+
and update jobs from paper forms.
|
|
50
|
+
- **Later:** full job management.
|
|
51
|
+
|
|
52
|
+
The job board is Flow's main view: a standard board of jobs by stage (a
|
|
53
|
+
column per stage, a card per job), with a list view of the same jobs. It
|
|
54
|
+
shows every job from the case system and from Flow, with its practice, due
|
|
55
|
+
date and department. Lab staff and the manager work from it.
|
|
56
|
+
|
|
57
|
+
Two parts follow the board (#48):
|
|
58
|
+
|
|
59
|
+
- **An intake reader.** A photo, a form or a note becomes a proposed job
|
|
60
|
+
action: update a job, create one, or add a note. A handwriting reader and a
|
|
61
|
+
low-cost decision model propose it; a person confirms it. Nothing changes
|
|
62
|
+
until a person accepts. The model steps are optional and cost money per
|
|
63
|
+
page, so the manager sees the month's cost.
|
|
64
|
+
- **A practice portal.** Practice staff sign in to follow their own jobs,
|
|
65
|
+
on desktop first, with a simpler view on phones. The server limits each
|
|
66
|
+
person to their practice.
|
|
67
|
+
|
|
68
|
+
Job management is a bundled module, built the same way as the integrations,
|
|
69
|
+
and a lab can remove it. Where the case system cannot take a change through
|
|
70
|
+
its API, the change becomes a short checklist for a person (#49).
|
|
71
|
+
|
|
36
72
|
## Standing decisions
|
|
37
73
|
|
|
38
74
|
### Why does Flow keep its own records?
|
|
@@ -58,7 +94,10 @@ not the product.
|
|
|
58
94
|
The case system, Flow and the accounting system each own their own records,
|
|
59
95
|
and the data moves both ways. Flow records which system each change came
|
|
60
96
|
from. When two systems disagree, Flow never overwrites one silently: it opens
|
|
61
|
-
an
|
|
97
|
+
an alert in the review queue. The alert shows each system's value and writes
|
|
98
|
+
nothing. A person fixes the record where they choose, then presses
|
|
99
|
+
**Resolved, re-check**: Flow checks that one difference again, and the alert
|
|
100
|
+
closes only when the systems agree.
|
|
62
101
|
|
|
63
102
|
### Why are approvals in Flow?
|
|
64
103
|
|
|
@@ -76,7 +115,8 @@ version; the sent one stays as it was, attributed to whoever sent it.
|
|
|
76
115
|
Dental cases carry health information, which Australian privacy law treats as
|
|
77
116
|
sensitive. Flow keeps the case number and the practice. It keeps a patient
|
|
78
117
|
reference only when a practice needs one printed on its invoice, and it keeps
|
|
79
|
-
no clinical notes or images.
|
|
118
|
+
no clinical notes or images. A form photo the intake reader reads is not kept
|
|
119
|
+
after its job is updated.
|
|
80
120
|
|
|
81
121
|
### Why does Flow keep its records in PostgreSQL only?
|
|
82
122
|
|
|
@@ -94,8 +134,9 @@ its own data, configuration and secrets.
|
|
|
94
134
|
|
|
95
135
|
## Out of scope
|
|
96
136
|
|
|
97
|
-
-
|
|
98
|
-
the
|
|
137
|
+
- Replacing the case system, for now. The case system owns the case record.
|
|
138
|
+
Flow's job board shows and updates the work, and does not do clinical
|
|
139
|
+
case management or production scheduling.
|
|
99
140
|
- Patient records, clinical notes, scans and images.
|
|
100
141
|
- Acting as the general ledger. Accounting software owns the ledger and the
|
|
101
142
|
bank feed.
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcforgelabs/flow",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.25",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@arcforgelabs/flow",
|
|
9
|
-
"version": "2026.10.
|
|
9
|
+
"version": "2026.10.25",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@clerk/backend": "3.23.2",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"@fontsource-variable/lora": "5.3.0",
|
|
20
20
|
"@fontsource-variable/nunito-sans": "5.3.0",
|
|
21
21
|
"@fontsource-variable/playfair-display": "5.3.0",
|
|
22
|
+
"@fontsource-variable/plus-jakarta-sans": "5.3.0",
|
|
22
23
|
"@fontsource-variable/space-grotesk": "5.3.0",
|
|
23
24
|
"drizzle-orm": "0.45.3",
|
|
24
25
|
"express": "5.3.0",
|
|
@@ -630,6 +631,15 @@
|
|
|
630
631
|
"url": "https://github.com/sponsors/ayuhito"
|
|
631
632
|
}
|
|
632
633
|
},
|
|
634
|
+
"node_modules/@fontsource-variable/plus-jakarta-sans": {
|
|
635
|
+
"version": "5.3.0",
|
|
636
|
+
"resolved": "https://registry.npmjs.org/@fontsource-variable/plus-jakarta-sans/-/plus-jakarta-sans-5.3.0.tgz",
|
|
637
|
+
"integrity": "sha512-/l/4r0yyWK9JzAlmA0LiYgGgmJe/Gswt4jTJEzr5QhJfwMbvJZDmYWyW0M4X7yCK69BajMVlV/Lx8g7WDc1+sw==",
|
|
638
|
+
"license": "OFL-1.1",
|
|
639
|
+
"funding": {
|
|
640
|
+
"url": "https://github.com/sponsors/ayuhito"
|
|
641
|
+
}
|
|
642
|
+
},
|
|
633
643
|
"node_modules/@fontsource-variable/space-grotesk": {
|
|
634
644
|
"version": "5.3.0",
|
|
635
645
|
"resolved": "https://registry.npmjs.org/@fontsource-variable/space-grotesk/-/space-grotesk-5.3.0.tgz",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcforgelabs/flow",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.25",
|
|
4
4
|
"description": "Invoicing, bill entry and a financial dashboard for labs, with Seazona and Xero integrations.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"@fontsource-variable/lora": "5.3.0",
|
|
45
45
|
"@fontsource-variable/nunito-sans": "5.3.0",
|
|
46
46
|
"@fontsource-variable/playfair-display": "5.3.0",
|
|
47
|
+
"@fontsource-variable/plus-jakarta-sans": "5.3.0",
|
|
47
48
|
"@fontsource-variable/space-grotesk": "5.3.0",
|
|
48
49
|
"drizzle-orm": "0.45.3",
|
|
49
50
|
"express": "5.3.0",
|
|
@@ -52,7 +52,7 @@ export function settingsEnvironment({ env, stored, adapters, secrets }) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
if (secrets) {
|
|
55
|
-
for (const name of adapter.setup.derivedKeys) merged[name] = deriveKey(secrets, name).toString('hex');
|
|
55
|
+
for (const name of adapter.setup.derivedKeys ?? []) merged[name] = deriveKey(secrets, name).toString('hex');
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
for (const [name, value] of Object.entries(env)) {
|
|
@@ -6,6 +6,7 @@ export const MONO_FONT = 'jetbrains-mono';
|
|
|
6
6
|
|
|
7
7
|
export const FAMILY_FONTS = {
|
|
8
8
|
harbour: ['nunito-sans', 'playfair-display'],
|
|
9
|
+
meridian: ['plus-jakarta-sans', 'playfair-display'],
|
|
9
10
|
beacon: ['atkinson-hyperlegible-next'],
|
|
10
11
|
tide: ['ibm-plex-sans'],
|
|
11
12
|
claw: ['instrument-sans'],
|
package/server/theme/themes.js
CHANGED
|
@@ -66,10 +66,64 @@ const HARBOUR = {
|
|
|
66
66
|
},
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
//
|
|
70
|
-
//
|
|
69
|
+
// Meridian: a dental laboratory's own look. Deep navy ink and filled buttons,
|
|
70
|
+
// a champagne highlight, warm stone pages and white cards. Plus Jakarta Sans
|
|
71
|
+
// for reading, Playfair Display at regular weight for page titles, square
|
|
72
|
+
// corners and widely tracked uppercase labels. Dark mode turns the navy into
|
|
73
|
+
// the page and the champagne into the accent.
|
|
74
|
+
const MERIDIAN_SHAPE = {
|
|
75
|
+
'--t-body': "'Plus Jakarta Sans Variable', 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif",
|
|
76
|
+
'--t-display': "'Playfair Display Variable', 'Playfair Display', Georgia, 'Times New Roman', serif",
|
|
77
|
+
'--t-data': "'JetBrains Mono Variable', 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
78
|
+
'--t-radius': '0px',
|
|
79
|
+
'--t-radius-lg': '2px',
|
|
80
|
+
'--t-stroke': '1px',
|
|
81
|
+
'--t-label-size': '12px',
|
|
82
|
+
'--t-label-weight': '600',
|
|
83
|
+
'--t-label-spacing': '.16em',
|
|
84
|
+
'--t-label-case': 'uppercase',
|
|
85
|
+
'--t-display-weight': '400',
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const MERIDIAN = {
|
|
89
|
+
label: 'Meridian',
|
|
90
|
+
description: 'Navy, champagne & stone',
|
|
91
|
+
source: 'flow',
|
|
92
|
+
light: {
|
|
93
|
+
'--t-bg': '#f6f3ef', '--t-s1': '#efe9e0', '--t-s2': '#e6ded1', '--t-paper': '#ffffff',
|
|
94
|
+
'--t-brd': '#e0dbd1', '--t-brd-hi': '#b8a685', '--t-stroke-color': '#d5cec2',
|
|
95
|
+
'--t-text': '#1d3444', '--t-strong': '#13242f', '--t-dim': '#4d6575', '--t-mute': '#526a7a',
|
|
96
|
+
'--t-accent': '#1d3444', '--t-accent-bg': '#faefdd', '--t-accent-brd': '#d4b07a',
|
|
97
|
+
'--t-brand': '#1d3444', '--t-brand-ink': '#f8dfb9',
|
|
98
|
+
'--t-primary': '#1d3444', '--t-on-primary': '#f8dfb9', '--t-ring': '#b08850',
|
|
99
|
+
'--t-warn': '#8a5a00', '--t-warn-bg': 'rgba(138, 90, 0, 0.08)', '--t-warn-brd': 'rgba(138, 90, 0, 0.32)',
|
|
100
|
+
'--t-danger': '#b42318', '--t-danger-bg': 'rgba(180, 35, 24, 0.07)', '--t-danger-brd': 'rgba(180, 35, 24, 0.40)',
|
|
101
|
+
'--t-success': '#22663f', '--t-success-bg': 'rgba(34, 102, 63, 0.08)',
|
|
102
|
+
...MERIDIAN_SHAPE,
|
|
103
|
+
'--t-shadow': '0 1px 2px rgba(29, 52, 68, 0.06)',
|
|
104
|
+
'color-scheme': 'light',
|
|
105
|
+
},
|
|
106
|
+
dark: {
|
|
107
|
+
'--t-bg': '#14252f', '--t-s1': '#1d3444', '--t-s2': '#26404f', '--t-paper': '#192d3a',
|
|
108
|
+
'--t-brd': '#2c4555', '--t-brd-hi': '#56707f', '--t-stroke-color': '#334d5e',
|
|
109
|
+
'--t-text': '#ece5d8', '--t-strong': '#fbf4e8', '--t-dim': '#b9c3c9', '--t-mute': '#a3b2bb',
|
|
110
|
+
'--t-accent': '#f8dfb9', '--t-accent-bg': 'rgba(248, 223, 185, 0.12)', '--t-accent-brd': 'rgba(248, 223, 185, 0.45)',
|
|
111
|
+
'--t-brand': '#f8dfb9', '--t-brand-ink': '#1d3444',
|
|
112
|
+
'--t-primary': '#f8dfb9', '--t-on-primary': '#1d3444', '--t-ring': '#f8dfb9',
|
|
113
|
+
'--t-warn': '#e7b75c', '--t-warn-bg': 'rgba(231, 183, 92, 0.12)', '--t-warn-brd': 'rgba(231, 183, 92, 0.32)',
|
|
114
|
+
'--t-danger': '#f2877b', '--t-danger-bg': 'rgba(242, 135, 123, 0.12)', '--t-danger-brd': 'rgba(242, 135, 123, 0.45)',
|
|
115
|
+
'--t-success': '#86d3a1', '--t-success-bg': 'rgba(134, 211, 161, 0.12)',
|
|
116
|
+
...MERIDIAN_SHAPE,
|
|
117
|
+
'--t-shadow': '0 1px 2px rgba(0, 0, 0, 0.30)',
|
|
118
|
+
'color-scheme': 'dark',
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Picker order: Flow's own (Harbour, Meridian), then the design directions
|
|
123
|
+
// Field leads with (Beacon, Tide, Claw, Knot, Dash), then the other OpenClaw
|
|
124
|
+
// families.
|
|
71
125
|
const { beacon, tide, claw, knot, dash, ...otherOpenclaw } = OPENCLAW_FAMILIES;
|
|
72
|
-
const FAMILIES = { harbour: HARBOUR, beacon, tide, claw, knot, dash, ...otherOpenclaw };
|
|
126
|
+
const FAMILIES = { harbour: HARBOUR, meridian: MERIDIAN, beacon, tide, claw, knot, dash, ...otherOpenclaw };
|
|
73
127
|
|
|
74
128
|
// --t-control: the edge of an input or an outlined button on --t-paper, the
|
|
75
129
|
// text colour faded toward the paper only as far as it still reads at 3:1.
|