@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.
Files changed (60) hide show
  1. package/bin/index.js +7 -0
  2. package/discovery-router/Dockerfile +18 -0
  3. package/discovery-router/README.md +99 -0
  4. package/discovery-router/package.json +13 -0
  5. package/discovery-router/registry.example.json +5 -0
  6. package/discovery-router/server.js +272 -0
  7. package/lib/account.js +120 -0
  8. package/lib/auth-dev-keys.js +12 -0
  9. package/lib/bankid.js +130 -0
  10. package/lib/cli.js +27 -0
  11. package/lib/command/bankid.js +45 -0
  12. package/lib/command/customer.js +108 -0
  13. package/lib/command/db.js +156 -0
  14. package/lib/command/env.js +114 -0
  15. package/lib/command/logs.js +143 -0
  16. package/lib/command/measure.js +81 -0
  17. package/lib/command/service.js +166 -0
  18. package/lib/command/setup.js +92 -0
  19. package/lib/command/shred.js +60 -0
  20. package/lib/compose/README.md +98 -0
  21. package/lib/compose/generate.js +375 -0
  22. package/lib/compose/manifests.js +108 -0
  23. package/lib/db/roles.js +118 -0
  24. package/lib/discovery/client.js +40 -0
  25. package/lib/engine/GUIDE.md +176 -0
  26. package/lib/engine/PROCESS.md +571 -0
  27. package/lib/engine/dbbuild.js +325 -0
  28. package/lib/engine/gen-schema-map.js +479 -0
  29. package/lib/engine/purge.js +137 -0
  30. package/lib/engine/schema-map.json +11016 -0
  31. package/lib/engine/seed.js +1045 -0
  32. package/lib/obc.js +72 -0
  33. package/lib/registry.js +123 -0
  34. package/lib/runtime.js +101 -0
  35. package/lib/service-token.js +40 -0
  36. package/lib/shred/README.md +118 -0
  37. package/lib/shred/audit.js +128 -0
  38. package/lib/shred/faker.js +545 -0
  39. package/lib/shred/index.js +126 -0
  40. package/lib/shred/scripts/base-partner-emails.sql +9 -0
  41. package/lib/shred/scripts/dev-accounts.sql +195 -0
  42. package/lib/shred/scripts/emails.sql +48 -0
  43. package/lib/shred/scripts/institution-browser.sql +3 -0
  44. package/lib/shred/scripts/notification-targets.sql +5 -0
  45. package/lib/shred/scripts/partners.sql +2 -0
  46. package/lib/shred/scripts/passwords.sql +8 -0
  47. package/lib/shred/scripts/personal-numbers.sql +177 -0
  48. package/lib/shred/scripts/phone-numbers.sql +22 -0
  49. package/lib/shred/scripts/salary-spec-reports.sql +5 -0
  50. package/lib/shred/scripts/service-activity-tracker-data.sql +4 -0
  51. package/lib/shred/scripts/service-core-objects.sql +19 -0
  52. package/lib/shred/scripts/service-event-stream.sql +2 -0
  53. package/lib/shred/scripts/service-integrations.sql +4 -0
  54. package/lib/shred/scripts/template.sql +4 -0
  55. package/lib/shred/scripts/x-service-billing.sql +34 -0
  56. package/lib/shred/scripts/xxx-history-tables.sql +25 -0
  57. package/lib/stub.js +8 -0
  58. package/local-postgres/Dockerfile +11 -0
  59. package/package.json +46 -0
  60. 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.