@dooer/dooer-test-env 1.0.0
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/bin/index.js +7 -0
- package/discovery-router/Dockerfile +18 -0
- package/discovery-router/README.md +99 -0
- package/discovery-router/package.json +13 -0
- package/discovery-router/registry.example.json +5 -0
- package/discovery-router/server.js +272 -0
- package/lib/account.js +120 -0
- package/lib/auth-dev-keys.js +12 -0
- package/lib/bankid.js +130 -0
- package/lib/cli.js +27 -0
- package/lib/command/bankid.js +45 -0
- package/lib/command/customer.js +108 -0
- package/lib/command/db.js +156 -0
- package/lib/command/env.js +114 -0
- package/lib/command/logs.js +143 -0
- package/lib/command/measure.js +81 -0
- package/lib/command/service.js +166 -0
- package/lib/command/setup.js +92 -0
- package/lib/command/shred.js +60 -0
- package/lib/compose/README.md +98 -0
- package/lib/compose/generate.js +375 -0
- package/lib/compose/manifests.js +108 -0
- package/lib/db/roles.js +118 -0
- package/lib/discovery/client.js +40 -0
- package/lib/engine/GUIDE.md +176 -0
- package/lib/engine/PROCESS.md +571 -0
- package/lib/engine/dbbuild.js +325 -0
- package/lib/engine/gen-schema-map.js +479 -0
- package/lib/engine/purge.js +137 -0
- package/lib/engine/schema-map.json +11016 -0
- package/lib/engine/seed.js +1045 -0
- package/lib/obc.js +72 -0
- package/lib/registry.js +123 -0
- package/lib/runtime.js +101 -0
- package/lib/service-token.js +40 -0
- package/lib/shred/README.md +118 -0
- package/lib/shred/audit.js +128 -0
- package/lib/shred/faker.js +545 -0
- package/lib/shred/index.js +126 -0
- package/lib/shred/scripts/base-partner-emails.sql +9 -0
- package/lib/shred/scripts/dev-accounts.sql +195 -0
- package/lib/shred/scripts/emails.sql +48 -0
- package/lib/shred/scripts/institution-browser.sql +3 -0
- package/lib/shred/scripts/notification-targets.sql +5 -0
- package/lib/shred/scripts/partners.sql +2 -0
- package/lib/shred/scripts/passwords.sql +8 -0
- package/lib/shred/scripts/personal-numbers.sql +177 -0
- package/lib/shred/scripts/phone-numbers.sql +22 -0
- package/lib/shred/scripts/salary-spec-reports.sql +5 -0
- package/lib/shred/scripts/service-activity-tracker-data.sql +4 -0
- package/lib/shred/scripts/service-core-objects.sql +19 -0
- package/lib/shred/scripts/service-event-stream.sql +2 -0
- package/lib/shred/scripts/service-integrations.sql +4 -0
- package/lib/shred/scripts/template.sql +4 -0
- package/lib/shred/scripts/x-service-billing.sql +34 -0
- package/lib/shred/scripts/xxx-history-tables.sql +25 -0
- package/lib/stub.js +8 -0
- package/local-postgres/Dockerfile +11 -0
- package/package.json +46 -0
- package/readme.md +92 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Seed a test account — how to run it
|
|
2
|
+
|
|
3
|
+
Copies all of one organization's data into another (a test entity). See **PROCESS.md** for how it
|
|
4
|
+
works; this is the run cheatsheet.
|
|
5
|
+
|
|
6
|
+
## Prerequisites
|
|
7
|
+
|
|
8
|
+
- **VPN** connected (the script talks to the `dooer-database` ClusterIP directly).
|
|
9
|
+
- **kubectl** access to the namespaces you use (`dooer-staging`, and `dooer-production` for real runs).
|
|
10
|
+
- **Node 18+** and a one-time `npm install` in this folder (installs `pg` + `pg-copy-streams`).
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
cd _wip/_jimmy/seed-test-account
|
|
14
|
+
npm install
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Run it via **`./seed-test-account.sh`** (not `node …` directly): the wrapper raises Node's heap so a
|
|
18
|
+
large org's uuid set fits in memory. Override the heap with `SEED_MAX_HEAP_MB` (default 8192).
|
|
19
|
+
|
|
20
|
+
Check VPN reachability first:
|
|
21
|
+
```bash
|
|
22
|
+
IP=$(kubectl get svc dooer-database -n dooer-staging -o jsonpath='{.spec.clusterIP}')
|
|
23
|
+
nc -z -w4 "$IP" 5432 && echo reachable
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## The golden rule: dry-run first
|
|
27
|
+
|
|
28
|
+
The tool is **dry-run by default** ("dummy" mode): it prints exactly what it would do and writes
|
|
29
|
+
nothing. Add `--execute` only once the plan looks right.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# 1) DRY-RUN — see the plan, no writes
|
|
33
|
+
./seed-test-account.sh --source <SOURCE_ORG> --target <TARGET_ORG> --source-namespace dooer-staging
|
|
34
|
+
|
|
35
|
+
# 2) EXECUTE — actually copy (same namespace)
|
|
36
|
+
./seed-test-account.sh --source <SOURCE_ORG> --target <TARGET_ORG> --source-namespace dooer-staging --execute
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Options
|
|
40
|
+
|
|
41
|
+
| flag | meaning |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `--source <uuid>` | org to copy FROM (required) |
|
|
44
|
+
| `--target <uuid>` | existing org to copy INTO |
|
|
45
|
+
| `--source-namespace <ns>` | default `dooer-staging` |
|
|
46
|
+
| `--target-namespace <ns>` | default = source; set differently to copy across clusters |
|
|
47
|
+
| `--execute` | actually write (omit = dry-run) |
|
|
48
|
+
| `--skip-files` | skip the S3 file copy (DB rows only). Default: files ARE copied. |
|
|
49
|
+
| `--skip-users` | skip copying referenced users missing from the target. Default: they ARE copied (customer-role emails anonymized). Same-namespace copies are a no-op regardless. |
|
|
50
|
+
| `--confirm-production` | REQUIRED to write when `--target-namespace dooer-production` |
|
|
51
|
+
| `--email <addr>` | scrub address (default `testcustomer@dooer.com`) |
|
|
52
|
+
| `--if-target-nonempty refuse\|insert` | if a copy table already has target rows (default `refuse`) |
|
|
53
|
+
| `--map <path>` | schema map (default `./schema-map.json`) |
|
|
54
|
+
|
|
55
|
+
## Common recipes
|
|
56
|
+
|
|
57
|
+
**Create a NEW target org and copy into it** (no pre-created target needed). The org is cloned from the
|
|
58
|
+
source's `companies` row (fresh id, your name, a unique short_name) and the owner is linked with role
|
|
59
|
+
`Owner`. The owner **user must already exist** in the target namespace — the tool never creates users.
|
|
60
|
+
It prints the new org id.
|
|
61
|
+
```bash
|
|
62
|
+
./seed-test-account.sh \
|
|
63
|
+
--source <SOURCE_ORG> --name "My Test Copy" --owner-user <EXISTING_USER_UUID> \
|
|
64
|
+
--source-namespace dooer-staging --execute
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Copy a production org into a brand-new STAGING test org** (safest — never writes to prod; the owner
|
|
68
|
+
must be a user that exists on staging):
|
|
69
|
+
```bash
|
|
70
|
+
./seed-test-account.sh \
|
|
71
|
+
--source <PROD_SOURCE_ORG> --source-namespace dooer-production \
|
|
72
|
+
--name "Large (copy of prod)" --owner-user <STAGING_USER_UUID> --target-namespace dooer-staging \
|
|
73
|
+
--execute
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Copy production data into an existing staging test org:**
|
|
77
|
+
```bash
|
|
78
|
+
./seed-test-account.sh \
|
|
79
|
+
--source <PROD_SOURCE_ORG> --source-namespace dooer-production \
|
|
80
|
+
--target <STAGING_TARGET_ORG> --target-namespace dooer-staging --execute
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Populate the production test entities (prod → prod, writes to production):**
|
|
84
|
+
```bash
|
|
85
|
+
# ALWAYS dry-run first:
|
|
86
|
+
./seed-test-account.sh --source <PROD_SOURCE> --target <PROD_TEST_ENTITY> --source-namespace dooer-production
|
|
87
|
+
# then, deliberately:
|
|
88
|
+
./seed-test-account.sh --source <PROD_SOURCE> --target <PROD_TEST_ENTITY> \
|
|
89
|
+
--source-namespace dooer-production --execute --confirm-production
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### The 2026-08 Dennis task (Large / Medium / Small)
|
|
93
|
+
|
|
94
|
+
Source = the real companies; target = the empty test entities Dennis created. **Confirm the direction
|
|
95
|
+
with a dry-run before executing** (the counts should show the source populated, target ~empty).
|
|
96
|
+
|
|
97
|
+
| size | `--source` (real) | `--target` (test entity) |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| Large | `14015598-3a63-4d10-9bf6-588ec365ec2e` | `4131681b-1099-49f8-930f-cb057310bb35` |
|
|
100
|
+
| Medium | `f8284a0f-82d0-41eb-aaa5-29b78db89b06` | `dcd126fb-0516-4ea4-a461-78a676d38524` |
|
|
101
|
+
| Small | `c67577e9-2ea1-4fe5-bf27-867e28d67274` | `8205b113-a039-441c-9ddd-a137d73717d4` |
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# dry-run each, e.g. Small:
|
|
105
|
+
./seed-test-account.sh --source c67577e9-2ea1-4fe5-bf27-867e28d67274 \
|
|
106
|
+
--target 8205b113-a039-441c-9ddd-a137d73717d4 --source-namespace dooer-production
|
|
107
|
+
# execute (prod write) when the plan is right:
|
|
108
|
+
./seed-test-account.sh --source c67577e9-2ea1-4fe5-bf27-867e28d67274 \
|
|
109
|
+
--target 8205b113-a039-441c-9ddd-a137d73717d4 --source-namespace dooer-production \
|
|
110
|
+
--execute --confirm-production
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Running over a flaky link (VPN) — resilience & resuming
|
|
114
|
+
|
|
115
|
+
The tool assumes a **stable, low-latency path to both databases**. A big copy holds connections open for a
|
|
116
|
+
long time; over a VPN that drops, expect trouble. Built-in resilience + how to survive the rest:
|
|
117
|
+
|
|
118
|
+
- **Reads auto-retry & reconnect.** Pass-1, the user discovery, the strategy/guard reads and the S3 file-id
|
|
119
|
+
read all reconnect a dropped connection and retry (exponential backoff). A flaky link no longer kills a read.
|
|
120
|
+
- **The write phase is still ONE transaction by default** — a mid-copy drop rolls the whole thing back cleanly
|
|
121
|
+
(no partial org). That's intentional, but it means a very large org may never finish in one unbroken window.
|
|
122
|
+
- **The remap is deterministic.** The id remap salt is derived from `(source, target)`, so **re-running the
|
|
123
|
+
exact same copy produces identical target ids**. That's what makes resuming/chunking safe.
|
|
124
|
+
- **Chunk a big org with `--only` / `--skip-tables`.** Pass-1 still scans every table (so cross-references
|
|
125
|
+
remap), but only the named tables are written. Re-run with the **same `--target`** and
|
|
126
|
+
`--if-target-nonempty insert` to copy the next chunk; ids line up because the salt is stable.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# chunk A (creates the org — note the id it prints), then chunk B into the SAME --target:
|
|
130
|
+
./seed-test-account.sh --source <S> --name "Big copy" --owner-user <U> \
|
|
131
|
+
--source-namespace dooer-production --target-namespace dooer-staging \
|
|
132
|
+
--only service_ledger.voucherJournal,service_ledger.voucherJournalLine --skip-files --execute
|
|
133
|
+
./seed-test-account.sh --source <S> --target <NEW_ORG_ID> \
|
|
134
|
+
--source-namespace dooer-production --target-namespace dooer-staging \
|
|
135
|
+
--skip-tables service_ledger.voucherJournal,service_ledger.voucherJournalLine \
|
|
136
|
+
--if-target-nonempty insert --execute
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Keep FK-linked integer-key tables in the SAME chunk.** Almost every id is a deterministic uuid, but a few
|
|
140
|
+
unique **integer** keys are assigned per run. Only one is cross-referenced: `service_core_objects.transactions`
|
|
141
|
+
(its `transactions_pk` twin is referenced by `documents2transactions`, `payments2transactions`,
|
|
142
|
+
`reports2transactions`, `transactions2transactions`, `transactions_fetch_logs`). Copy `transactions` **together
|
|
143
|
+
with those five** in one invocation (don't split them across chunks). Everything else is safe to split freely.
|
|
144
|
+
|
|
145
|
+
## Verify a copy
|
|
146
|
+
|
|
147
|
+
After executing, spot-check that counts match and references are intact:
|
|
148
|
+
```sql
|
|
149
|
+
-- source vs target should match (read via the -1 replica pod is fine):
|
|
150
|
+
SELECT (SELECT count(*) FROM service_ledger."voucherJournal" WHERE "organizationId"='<SOURCE>'),
|
|
151
|
+
(SELECT count(*) FROM service_ledger."voucherJournal" WHERE "organizationId"='<TARGET>');
|
|
152
|
+
-- emails scrubbed:
|
|
153
|
+
SELECT count(*) FROM service_employees.employee WHERE "organizationId"='<TARGET>'
|
|
154
|
+
AND email <> 'testcustomer@dooer.com'; -- expect 0
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Notes & gotchas
|
|
158
|
+
|
|
159
|
+
- **Reads go to the primary via the ClusterIP;** the `dooer-database-1` pod is a **read-only replica**,
|
|
160
|
+
so don't try to write through `kubectl exec` into it — the script connects to the write endpoint.
|
|
161
|
+
- **A big org takes a few minutes**, dominated by pass 1 (reading source ids + building the uuid set).
|
|
162
|
+
Writes use `COPY` and are fast. Watch `[pass1 n/N]` then `[copy n/N]` on stderr; redirect with
|
|
163
|
+
`2>&1 | tee /tmp/run.out` rather than piping through `tail` (which buffers).
|
|
164
|
+
- **Memory:** run via `./seed-test-account.sh` (raised heap). A very large org can still need more — bump
|
|
165
|
+
`SEED_MAX_HEAP_MB` (e.g. `SEED_MAX_HEAP_MB=16384 ./seed-test-account.sh …`).
|
|
166
|
+
- **Files (S3):** copied by default *after* the DB commit — reads the source env's Ceph RGW and writes
|
|
167
|
+
the target env's (needs kubectl to both `service-file-storage` pods; VPN to the RGW ClusterIPs). It is
|
|
168
|
+
best-effort/non-transactional: if interrupted, the DB is already committed — just **re-run** (idempotent
|
|
169
|
+
overwrite) to finish the files, or run with `--skip-files` to skip them. `missing-in-source` counts are
|
|
170
|
+
files that no longer exist in either source bucket (deleted); `failed` should be 0.
|
|
171
|
+
- **Change a copy/ignore or a uniqueness decision** by editing `schema-map.json` (`action`, or a
|
|
172
|
+
column's `strategy`) — no code change. Re-measure + `node gen-schema-map.js` after a schema change.
|
|
173
|
+
- **Creating a brand-new target** (`--name` / `--owner-user`) works: it clones the source `companies`
|
|
174
|
+
row and links the owner (role `Owner`). The owner user must already exist in the target namespace.
|
|
175
|
+
- The tool **never deletes** and **never copies users**. To reset a throwaway *test* target you made,
|
|
176
|
+
delete its rows manually (see the cleanup snippet in the repo history) — never against a real org.
|