@forestadmin/datasource-demo-fintech 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 (45) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +40 -0
  3. package/dist/customizations/aml_alerts.d.ts +3 -0
  4. package/dist/customizations/aml_alerts.js +135 -0
  5. package/dist/customizations/cards.d.ts +3 -0
  6. package/dist/customizations/cards.js +95 -0
  7. package/dist/customizations/chargebacks.d.ts +3 -0
  8. package/dist/customizations/chargebacks.js +271 -0
  9. package/dist/customizations/customers.d.ts +3 -0
  10. package/dist/customizations/customers.js +15 -0
  11. package/dist/customizations/kyc_cases.d.ts +3 -0
  12. package/dist/customizations/kyc_cases.js +105 -0
  13. package/dist/customizations/kyc_documents.d.ts +3 -0
  14. package/dist/customizations/kyc_documents.js +62 -0
  15. package/dist/customizations/refund_requests.d.ts +3 -0
  16. package/dist/customizations/refund_requests.js +151 -0
  17. package/dist/customizations/sar_reports.d.ts +3 -0
  18. package/dist/customizations/sar_reports.js +27 -0
  19. package/dist/customizations/utils.d.ts +21 -0
  20. package/dist/customizations/utils.js +22 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.js +97 -0
  23. package/dist/seed/aml.d.ts +9 -0
  24. package/dist/seed/aml.js +131 -0
  25. package/dist/seed/cards.d.ts +9 -0
  26. package/dist/seed/cards.js +57 -0
  27. package/dist/seed/chargebacks.d.ts +9 -0
  28. package/dist/seed/chargebacks.js +118 -0
  29. package/dist/seed/customers.d.ts +9 -0
  30. package/dist/seed/customers.js +106 -0
  31. package/dist/seed/dates.d.ts +7 -0
  32. package/dist/seed/dates.js +28 -0
  33. package/dist/seed/index.d.ts +9 -0
  34. package/dist/seed/index.js +39 -0
  35. package/dist/seed/kyc.d.ts +9 -0
  36. package/dist/seed/kyc.js +102 -0
  37. package/dist/seed/pools.d.ts +27 -0
  38. package/dist/seed/pools.js +296 -0
  39. package/dist/seed/refunds.d.ts +9 -0
  40. package/dist/seed/refunds.js +72 -0
  41. package/dist/seed/types.d.ts +17 -0
  42. package/dist/seed/types.js +5 -0
  43. package/dist/seed/utils.d.ts +16 -0
  44. package/dist/seed/utils.js +40 -0
  45. package/package.json +33 -0
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = seedAml;
4
+ const dates_1 = require("./dates");
5
+ const pools_1 = require("./pools");
6
+ const utils_1 = require("./utils");
7
+ function amlSeverity(risk, sanctioned, atype) {
8
+ if (sanctioned || atype === 'SANCTIONS_MATCH')
9
+ return (0, utils_1.choices)(['HIGH', 'CRITICAL'], [40, 60]);
10
+ return (0, utils_1.choices)(pools_1.AML_SEVERITIES, { HIGH: [0, 1, 5, 4], MEDIUM: [1, 5, 3, 1], LOW: [6, 3, 1, 0] }[risk]);
11
+ }
12
+ function alertNotes(status) {
13
+ if (status === 'CLEARED') {
14
+ return (0, utils_1.pick)(['False positive — name overlap.', 'Cleared after review.']);
15
+ }
16
+ if (status === 'ESCALATED')
17
+ return (0, utils_1.pick)(['Escalated to MLRO.', 'Under enhanced due diligence.']);
18
+ return null;
19
+ }
20
+ /**
21
+ * Raises 70 AML alerts, weighting customers by risk/PEP/sanctions, then files SARs
22
+ * for the escalated ones. A filed SAR pushes its source alert to SAR_FILED so the
23
+ * two collections always tell the same story.
24
+ */
25
+ async function seedAml(knex, customers) {
26
+ await knex.schema.createTable('aml_alerts', table => {
27
+ table.increments('id').primary();
28
+ table.integer('customer_id');
29
+ table.string('alert_type');
30
+ table.string('severity');
31
+ table.string('status');
32
+ table.datetime('triggered_at');
33
+ table.string('resolution_notes');
34
+ table.string('sar_reference');
35
+ table.datetime('resolved_at');
36
+ });
37
+ await knex.schema.createTable('sar_reports', table => {
38
+ table.increments('id').primary();
39
+ table.integer('alert_id');
40
+ table.integer('customer_id');
41
+ table.string('reference');
42
+ table.string('status');
43
+ table.string('activity_type');
44
+ table.date('activity_start_date');
45
+ table.date('activity_end_date');
46
+ table.float('total_amount');
47
+ table.integer('transaction_count');
48
+ table.string('narrative');
49
+ table.datetime('filed_at');
50
+ table.datetime('created_at');
51
+ });
52
+ const weights = customers.map(c => {
53
+ let w = { HIGH: 6, MEDIUM: 2, LOW: 1 }[c.risk_rating];
54
+ if (c.is_pep)
55
+ w += 4;
56
+ if (c.is_sanctioned)
57
+ w += 8;
58
+ return w;
59
+ });
60
+ const alerts = [];
61
+ let sarSeq = 0;
62
+ for (let aid = 1; aid <= 70; aid += 1) {
63
+ const c = (0, utils_1.choices)(customers, weights);
64
+ let atype;
65
+ if (c.is_sanctioned) {
66
+ atype = (0, utils_1.chance)(0.7) ? 'SANCTIONS_MATCH' : (0, utils_1.pick)(pools_1.ATYPES);
67
+ }
68
+ else {
69
+ atype = (0, utils_1.chance)(0.08) ? 'SANCTIONS_MATCH' : (0, utils_1.pick)(pools_1.ATYPES.filter(t => t !== 'SANCTIONS_MATCH'));
70
+ }
71
+ const st = (0, utils_1.choices)(pools_1.AML_STATUSES, [30, 28, 22, 20]);
72
+ const trig = (0, utils_1.randint)(1, 130);
73
+ let sarRef = null;
74
+ if (st === 'ESCALATED' && (c.risk_rating === 'HIGH' || c.is_sanctioned || (0, utils_1.chance)(0.5))) {
75
+ sarSeq += 1;
76
+ sarRef = `SAR-2026-${String(sarSeq).padStart(5, '0')}`;
77
+ }
78
+ const resolved = ['CLEARED', 'ESCALATED'].includes(st);
79
+ alerts.push({
80
+ id: aid,
81
+ customer_id: c.id,
82
+ alert_type: atype,
83
+ severity: amlSeverity(c.risk_rating, c.is_sanctioned, atype),
84
+ status: st,
85
+ triggered_at: (0, dates_1.daysAgo)(trig),
86
+ resolution_notes: alertNotes(st),
87
+ sar_reference: sarRef,
88
+ resolved_at: resolved ? (0, dates_1.daysAgo)((0, utils_1.randint)(1, Math.max(2, trig - 1))) : null,
89
+ linkedSarRef: sarRef,
90
+ });
91
+ }
92
+ const sars = [];
93
+ let sid = 0;
94
+ for (const a of alerts.filter(x => x.linkedSarRef)) {
95
+ sid += 1;
96
+ const start = (0, utils_1.randint)(40, 120);
97
+ const end = (0, utils_1.randint)(5, 35);
98
+ const status = (0, utils_1.choices)(pools_1.SAR_STATUSES, [25, 25, 50]);
99
+ const filedAt = (0, utils_1.chance)(0.6) ? (0, dates_1.daysAgo)((0, utils_1.randint)(1, end)) : null;
100
+ const createdAt = (0, dates_1.daysAgo)(end + (0, utils_1.randint)(1, 5));
101
+ sars.push({
102
+ id: sid,
103
+ alert_id: a.id,
104
+ customer_id: a.customer_id,
105
+ reference: a.linkedSarRef,
106
+ status,
107
+ activity_type: a.alert_type,
108
+ activity_start_date: (0, dates_1.dayOnlyAgo)(start),
109
+ activity_end_date: (0, dates_1.dayOnlyAgo)(end),
110
+ total_amount: (0, utils_1.round2)((0, utils_1.uniform)(8000, 240000)),
111
+ transaction_count: (0, utils_1.randint)(3, 80),
112
+ narrative: `Suspicious activity consistent with ${a.alert_type
113
+ .replace(/_/g, ' ')
114
+ .toLowerCase()} detected over ${start - end} days; cumulative value exceeds internal thresholds. Funds movement reviewed by compliance and escalated to the financial intelligence unit.`,
115
+ filed_at: filedAt,
116
+ created_at: createdAt,
117
+ });
118
+ // Coherence: an alert with a linked SAR reflects that SAR's state.
119
+ if (['FILED', 'SUBMITTED'].includes(status)) {
120
+ a.status = 'SAR_FILED';
121
+ a.resolved_at = a.resolved_at || filedAt || createdAt;
122
+ a.resolution_notes = `SAR ${a.linkedSarRef} filed with the FIU.`;
123
+ }
124
+ else {
125
+ a.status = 'ESCALATED';
126
+ }
127
+ }
128
+ await (0, utils_1.insertAll)(knex, 'aml_alerts', alerts.map(({ linkedSarRef, ...row }) => row));
129
+ await (0, utils_1.insertAll)(knex, 'sar_reports', sars);
130
+ }
131
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW1sLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlZWQvYW1sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBMkNBLDBCQXdIQztBQWhLRCxtQ0FBOEM7QUFDOUMsbUNBQTZFO0FBQzdFLG1DQUFxRjtBQVlyRixTQUFTLFdBQVcsQ0FBQyxJQUFZLEVBQUUsVUFBbUIsRUFBRSxLQUFhO0lBQ25FLElBQUksVUFBVSxJQUFJLEtBQUssS0FBSyxpQkFBaUI7UUFBRSxPQUFPLElBQUEsZUFBTyxFQUFDLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFOUYsT0FBTyxJQUFBLGVBQU8sRUFDWixzQkFBYyxFQUNkLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FDN0QsSUFBaUMsQ0FDbEMsQ0FDRixDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsVUFBVSxDQUFDLE1BQWM7SUFDaEMsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDekIsT0FBTyxJQUFBLFlBQUksRUFBQyxDQUFDLGdDQUFnQyxFQUFFLHVCQUF1QixDQUFDLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBRUQsSUFBSSxNQUFNLEtBQUssV0FBVztRQUFFLE9BQU8sSUFBQSxZQUFJLEVBQUMsQ0FBQyxvQkFBb0IsRUFBRSwrQkFBK0IsQ0FBQyxDQUFDLENBQUM7SUFFakcsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNZLEtBQUssVUFBVSxPQUFPLENBQUMsSUFBVSxFQUFFLFNB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
@@ -0,0 +1,9 @@
1
+ import type { Card, Customer } from './types';
2
+ import type { Knex } from 'knex';
3
+ export interface CardsResult {
4
+ cards: Card[];
5
+ cardsByCust: Record<number, Card[]>;
6
+ }
7
+ /** Issues 1–3 cards per customer; blocked cards carry a reason and a block date. */
8
+ export default function seedCards(knex: Knex, customers: Customer[]): Promise<CardsResult>;
9
+ //# sourceMappingURL=cards.d.ts.map
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = seedCards;
4
+ const dates_1 = require("./dates");
5
+ const pools_1 = require("./pools");
6
+ const utils_1 = require("./utils");
7
+ /** Issues 1–3 cards per customer; blocked cards carry a reason and a block date. */
8
+ async function seedCards(knex, customers) {
9
+ var _a;
10
+ await knex.schema.createTable('cards', table => {
11
+ table.increments('id').primary();
12
+ table.integer('customer_id');
13
+ table.string('card_type');
14
+ table.string('status');
15
+ table.string('last_four_digits');
16
+ table.datetime('issued_at');
17
+ table.date('expires_at');
18
+ table.string('blocked_reason');
19
+ table.datetime('blocked_at');
20
+ });
21
+ const cards = [];
22
+ const cardsByCust = {};
23
+ let cid = 0;
24
+ for (const c of customers) {
25
+ const n = (0, utils_1.randint)(1, 3);
26
+ for (let k = 0; k < n; k += 1) {
27
+ cid += 1;
28
+ const st = (0, utils_1.choices)(pools_1.CARD_STATUSES, [70, 11, 8, 7, 4]);
29
+ const issued = (0, utils_1.randint)(20, 380);
30
+ const card = {
31
+ id: cid,
32
+ customer_id: c.id,
33
+ card_type: (0, utils_1.choices)(pools_1.CARD_TYPES, [55, 45]),
34
+ status: st,
35
+ last_four_digits: String((0, utils_1.randint)(0, 9999)).padStart(4, '0'),
36
+ issued_at: (0, dates_1.daysAgo)(issued),
37
+ expires_at: (0, dates_1.dayOnlyAgo)(-(0, utils_1.randint)(365, 1460)),
38
+ blocked_reason: null,
39
+ blocked_at: null,
40
+ };
41
+ if (st === 'BLOCKED') {
42
+ card.blocked_reason = (0, utils_1.pick)([
43
+ 'Suspected fraud',
44
+ 'Reported lost',
45
+ 'Compliance hold',
46
+ 'Customer request',
47
+ ]);
48
+ card.blocked_at = (0, dates_1.daysAgo)((0, utils_1.randint)(1, Math.max(2, issued - 5)));
49
+ }
50
+ cards.push(card);
51
+ (cardsByCust[_a = c.id] || (cardsByCust[_a] = [])).push(card);
52
+ }
53
+ }
54
+ await (0, utils_1.insertAll)(knex, 'cards', cards);
55
+ return { cards, cardsByCust };
56
+ }
57
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FyZHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VlZC9jYXJkcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWFBLDRCQXNEQztBQWhFRCxtQ0FBOEM7QUFDOUMsbUNBQW9EO0FBQ3BELG1DQUE0RDtBQU81RCxvRkFBb0Y7QUFDckUsS0FBSyxVQUFVLFNBQVMsQ0FBQyxJQUFVLEVBQUUsU0FBcUI7O0lBQ3ZFLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxFQUFFO1FBQzdDLEtBQUssQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDakMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUM3QixLQUFLLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzFCLEtBQUssQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDdkIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBQ2pDLEtBQUssQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDNUIsS0FBSyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUN6QixLQUFLLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDL0IsS0FBSyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUMvQixDQUFDLENBQUMsQ0FBQztJQUVILE1BQU0sS0FBSyxHQUFXLEVBQUUsQ0FBQztJQUN6QixNQUFNLFdBQVcsR0FBMkIsRUFBRSxDQUFDO0lBQy9DLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztJQUVaLEtBQUssTUFBTSxDQUFDLElBQUksU0FBUyxFQUFFLENBQUM7UUFDMUIsTUFBTSxDQUFDLEdBQUcsSUFBQSxlQUFPLEVBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRXhCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQzlCLEdBQUcsSUFBSSxDQUFDLENBQUM7WUFDVCxNQUFNLEVBQUUsR0FBRyxJQUFBLGVBQU8sRUFBQyxxQkFBYSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDckQsTUFBTSxNQUFNLEdBQUcsSUFBQSxlQUFPLEVBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ2hDLE1BQU0sSUFBSSxHQUFTO2dCQUNqQixFQUFFLEVBQUUsR0FBRztnQkFDUCxXQUFXLEVBQUUsQ0FBQyxDQUFDLEVBQUU7Z0JBQ2pCLFNBQVMsRUFBRSxJQUFBLGVBQU8sRUFBQyxrQkFBVSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUN4QyxNQUFNLEVBQUUsRUFBRTtnQkFDVixnQkFBZ0IsRUFBRSxNQUFNLENBQUMsSUFBQSxlQUFPLEVBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7Z0JBQzNELFNBQVMsRUFBRSxJQUFBLGVBQU8sRUFBQyxNQUFNLENBQUM7Z0JBQzFCLFVBQVUsRUFBRSxJQUFBLGtCQUFVLEVBQUMsQ0FBQyxJQUFBLGVBQU8sRUFBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBQzNDLGNBQWMsRUFBRSxJQUFJO2dCQUNwQixVQUFVLEVBQUUsSUFBSTthQUNqQixDQUFDO1lBRUYsSUFBSSxFQUFFLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ3JCLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBQSxZQUFJLEVBQUM7b0JBQ3pCLGlCQUFpQjtvQkFDakIsZUFBZTtvQkFDZixpQkFBaUI7b0JBQ2pCLGtCQUFrQjtpQkFDbkIsQ0FBQyxDQUFDO2dCQUNILElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBQSxlQUFPLEVBQUMsSUFBQSxlQUFPLEVBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDakUsQ0FBQztZQUVELEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDakIsQ0FBQyxXQUFXLE1BQUMsQ0FBQyxDQUFDLEVBQUUsTUFBaEIsV0FBVyxPQUFXLEVBQUUsRUFBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN4QyxDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sSUFBQSxpQkFBUyxFQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFFdEMsT0FBTyxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUNoQyxDQUFDIn0=
@@ -0,0 +1,9 @@
1
+ import type { Card, Customer, Refund } from './types';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Spreads chargebacks over 60 customers (1–5 each), each tied to one of the
5
+ * customer's cards and, for customer disputes, occasionally to an existing refund
6
+ * request — so the dispute trail links back to a real refund.
7
+ */
8
+ export default function seedChargebacks(knex: Knex, customers: Customer[], cardsByCust: Record<number, Card[]>, refundsByCust: Record<number, Refund[]>): Promise<void>;
9
+ //# sourceMappingURL=chargebacks.d.ts.map
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = seedChargebacks;
4
+ const dates_1 = require("./dates");
5
+ const pools_1 = require("./pools");
6
+ const utils_1 = require("./utils");
7
+ /**
8
+ * Spreads chargebacks over 60 customers (1–5 each), each tied to one of the
9
+ * customer's cards and, for customer disputes, occasionally to an existing refund
10
+ * request — so the dispute trail links back to a real refund.
11
+ */
12
+ async function seedChargebacks(knex, customers, cardsByCust, refundsByCust) {
13
+ await knex.schema.createTable('chargebacks', table => {
14
+ table.increments('id').primary();
15
+ table.string('reference');
16
+ table.integer('customer_id');
17
+ table.integer('card_id');
18
+ table.integer('refund_request_id');
19
+ table.string('transaction_id');
20
+ table.string('merchant_name');
21
+ table.string('merchant_category');
22
+ table.string('mcc_code');
23
+ table.float('transaction_amount');
24
+ table.string('transaction_currency');
25
+ table.date('transaction_date');
26
+ table.float('amount');
27
+ table.string('currency');
28
+ table.string('network');
29
+ table.string('reason_code');
30
+ table.string('reason_description');
31
+ table.string('source');
32
+ table.string('processor_dispute_id');
33
+ table.string('status');
34
+ table.datetime('filed_at');
35
+ table.datetime('representment_deadline');
36
+ table.datetime('decision_at');
37
+ table.string('evidence_url');
38
+ table.datetime('evidence_submitted_at');
39
+ table.boolean('provisional_credit_issued');
40
+ table.string('analyst_email');
41
+ table.string('resolution_notes');
42
+ table.datetime('created_at');
43
+ table.datetime('updated_at');
44
+ });
45
+ const chargebacks = [];
46
+ let cbid = 0;
47
+ const cbCusts = (0, utils_1.sample)(customers, 60);
48
+ const plan = [];
49
+ for (const c of cbCusts) {
50
+ for (let k = 0; k < (0, utils_1.choices)([1, 2, 3, 5], [46, 30, 17, 7]); k += 1)
51
+ plan.push(c);
52
+ }
53
+ for (const c of (0, utils_1.shuffle)(plan)) {
54
+ cbid += 1;
55
+ const [merch, cat, mcc] = (0, utils_1.pick)(pools_1.MERCHANTS);
56
+ const card = (0, utils_1.pick)(cardsByCust[c.id]);
57
+ const txAmount = (0, utils_1.round2)((0, utils_1.uniform)(12, 2400));
58
+ const amount = (0, utils_1.chance)(0.35) ? (0, utils_1.round2)(txAmount * (0, utils_1.uniform)(0.2, 0.9)) : txAmount; // partial disputes
59
+ const status = (0, utils_1.choices)(pools_1.CB_STATUS, [22, 16, 13, 13, 5, 5, 3, 3]);
60
+ const filed = (0, utils_1.randint)(1, 110);
61
+ const [rcode, rdesc] = (0, utils_1.pick)(pools_1.CB_REASONS);
62
+ const src = (0, utils_1.choices)(pools_1.SOURCES, [55, 30, 15]);
63
+ let rr = null;
64
+ if (src === 'CUSTOMER_DISPUTE' && refundsByCust[c.id] && (0, utils_1.chance)(0.4)) {
65
+ rr = (0, utils_1.pick)(refundsByCust[c.id]).id;
66
+ }
67
+ const decided = ['WON', 'LOST', 'ACCEPTED'].includes(status);
68
+ const presented = [
69
+ 'PRESENTED',
70
+ 'REPRESENTED',
71
+ 'WON',
72
+ 'LOST',
73
+ 'ARBITRATION',
74
+ 'PRE_ARBITRATION',
75
+ ].includes(status);
76
+ chargebacks.push({
77
+ id: cbid,
78
+ reference: `CB-2026-${String(cbid).padStart(5, '0')}`,
79
+ customer_id: c.id,
80
+ card_id: card.id,
81
+ refund_request_id: rr,
82
+ transaction_id: `TXN-${(0, utils_1.randint)(10000, 99999)}`,
83
+ merchant_name: merch,
84
+ merchant_category: cat,
85
+ mcc_code: mcc,
86
+ transaction_amount: txAmount,
87
+ transaction_currency: 'EUR',
88
+ transaction_date: (0, dates_1.dayOnlyAgo)(filed + (0, utils_1.randint)(2, 20)),
89
+ amount,
90
+ currency: 'EUR',
91
+ network: (0, utils_1.pick)(pools_1.NETWORKS),
92
+ reason_code: rcode,
93
+ reason_description: rdesc,
94
+ source: src,
95
+ processor_dispute_id: (0, utils_1.chance)(0.7) ? `ADYEN-DSP-${(0, utils_1.randint)(100000, 999999)}` : null,
96
+ status,
97
+ filed_at: (0, dates_1.daysAgo)(filed),
98
+ representment_deadline: (0, dates_1.daysAgo)(filed - 30),
99
+ decision_at: decided ? (0, dates_1.daysAgo)((0, utils_1.randint)(1, Math.max(2, filed - 2))) : null,
100
+ evidence_url: presented && (0, utils_1.chance)(0.7) ? `https://disputes.neobank.eu/evidence/${cbid}.zip` : null,
101
+ evidence_submitted_at: presented && (0, utils_1.chance)(0.7) ? (0, dates_1.daysAgo)((0, utils_1.randint)(1, Math.max(2, filed - 1))) : null,
102
+ provisional_credit_issued: (0, utils_1.chance)(0.4),
103
+ analyst_email: (0, utils_1.chance)(0.6) ? (0, utils_1.pick)(pools_1.ANALYSTS) : null,
104
+ resolution_notes: decided
105
+ ? (0, utils_1.pick)([
106
+ 'Won at representment.',
107
+ 'Lost — insufficient evidence.',
108
+ 'Accepted liability.',
109
+ 'Pending issuer response.',
110
+ ])
111
+ : null,
112
+ created_at: (0, dates_1.daysAgo)(filed > 2 ? filed : 1),
113
+ updated_at: (0, dates_1.daysAgo)((0, utils_1.randint)(0, Math.max(1, filed - 1))),
114
+ });
115
+ }
116
+ await (0, utils_1.insertAll)(knex, 'chargebacks', chargebacks);
117
+ }
118
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcmdlYmFja3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VlZC9jaGFyZ2ViYWNrcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXNCQSxrQ0FxSEM7QUF4SUQsbUNBQThDO0FBQzlDLG1DQUF3RjtBQUN4RixtQ0FVaUI7QUFFakI7Ozs7R0FJRztBQUNZLEtBQUssVUFBVSxlQUFlLENBQzNDLElBQVUsRUFDVixTQUFxQixFQUNyQixXQUFtQyxFQUNuQyxhQUF1QztJQUV2QyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsRUFBRTtRQUNuRCxLQUFLLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2pDLEtBQUssQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDMUIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUM3QixLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3pCLEtBQUssQ0FBQyxPQUFPLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUNuQyxLQUFLLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDL0IsS0FBSyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUM5QixLQUFLLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDbEMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN6QixLQUFLLENBQUMsS0FBSyxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDbEMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1FBQ3JDLEtBQUssQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUMvQixLQUFLLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3RCLEtBQUssQ0FBQyxNQUFN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
@@ -0,0 +1,9 @@
1
+ import type { Customer } from './types';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Builds the customer base, then derives every other table from it. Risk rating,
5
+ * PEP/sanctions flags and onboarding status are correlated on purpose: sanctioned
6
+ * customers never clear onboarding, high-risk ones skew towards risky countries.
7
+ */
8
+ export default function seedCustomers(knex: Knex): Promise<Customer[]>;
9
+ //# sourceMappingURL=customers.d.ts.map
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = seedCustomers;
4
+ const dates_1 = require("./dates");
5
+ const pools_1 = require("./pools");
6
+ const utils_1 = require("./utils");
7
+ const N = 150;
8
+ /**
9
+ * Builds the customer base, then derives every other table from it. Risk rating,
10
+ * PEP/sanctions flags and onboarding status are correlated on purpose: sanctioned
11
+ * customers never clear onboarding, high-risk ones skew towards risky countries.
12
+ */
13
+ async function seedCustomers(knex) {
14
+ await knex.schema.createTable('customers', table => {
15
+ table.increments('id').primary();
16
+ table.string('first_name');
17
+ table.string('last_name');
18
+ table.string('email');
19
+ table.string('phone');
20
+ table.date('date_of_birth');
21
+ table.string('nationality');
22
+ table.string('country_of_residence');
23
+ table.string('address_line1');
24
+ table.string('address_line2');
25
+ table.string('city');
26
+ table.string('postal_code');
27
+ table.string('country');
28
+ table.string('onboarding_status');
29
+ table.string('risk_rating');
30
+ table.boolean('is_pep');
31
+ table.boolean('is_sanctioned');
32
+ table.string('referral_code');
33
+ table.datetime('created_at');
34
+ table.datetime('updated_at');
35
+ });
36
+ const nHigh = Math.round(N * 0.2);
37
+ const nMed = Math.round(N * 0.33);
38
+ const riskPlan = (0, utils_1.shuffle)([
39
+ ...Array(nHigh).fill('HIGH'),
40
+ ...Array(nMed).fill('MEDIUM'),
41
+ ...Array(N - nHigh - nMed).fill('LOW'),
42
+ ]);
43
+ const ids = Array.from({ length: N }, (_, i) => i + 1);
44
+ const highIds = ids.filter(i => riskPlan[i - 1] === 'HIGH');
45
+ const elevatedIds = ids.filter(i => ['HIGH', 'MEDIUM'].includes(riskPlan[i - 1]));
46
+ const sanctionedIds = new Set((0, utils_1.sample)(highIds, Math.max(2, Math.round(N * 0.035))));
47
+ const pepIds = new Set((0, utils_1.sample)(elevatedIds, Math.max(4, Math.round(N * 0.08))));
48
+ const customers = [];
49
+ const seenEmails = new Set();
50
+ for (let i = 1; i <= N; i += 1) {
51
+ const fn = pools_1.FIRST[(i - 1) % pools_1.FIRST.length];
52
+ const ln = pools_1.LAST[(i * 7) % pools_1.LAST.length];
53
+ const risk = riskPlan[i - 1];
54
+ const sanctioned = sanctionedIds.has(i);
55
+ const pep = pepIds.has(i);
56
+ let cor;
57
+ let onb;
58
+ if (risk === 'HIGH') {
59
+ cor = (0, utils_1.chance)(0.5) ? (0, utils_1.pick)(pools_1.HIGH_RISK_COUNTRIES) : (0, utils_1.pick)(pools_1.COUNTRIES);
60
+ onb = (0, utils_1.pick)(['APPROVED', 'PENDING_REVIEW', 'REJECTED']);
61
+ }
62
+ else if (risk === 'MEDIUM') {
63
+ cor = (0, utils_1.pick)(pools_1.COUNTRIES);
64
+ onb = (0, utils_1.pick)(['APPROVED', 'APPROVED', 'PENDING_REVIEW']);
65
+ }
66
+ else {
67
+ cor = (0, utils_1.pick)(pools_1.COUNTRIES);
68
+ onb = (0, utils_1.pick)(['APPROVED', 'APPROVED', 'APPROVED', 'STARTED']);
69
+ }
70
+ if (sanctioned)
71
+ onb = (0, utils_1.pick)(['REJECTED', 'PENDING_REVIEW']); // never clears onboarding
72
+ const country = pools_1.CITIES[cor] ? cor : (0, utils_1.pick)(pools_1.COUNTRIES);
73
+ const [city, postal] = (0, utils_1.pick)(pools_1.CITIES[country]);
74
+ const created = (0, utils_1.randint)(60, 220);
75
+ const slug = (0, pools_1.deaccent)(`${fn.toLowerCase()}.${ln.toLowerCase()}`);
76
+ let email = `${slug}@example.com`;
77
+ if (seenEmails.has(email))
78
+ email = `${slug}${i}@example.com`; // names repeat at scale
79
+ seenEmails.add(email);
80
+ customers.push({
81
+ id: i,
82
+ first_name: fn,
83
+ last_name: ln,
84
+ email,
85
+ phone: `+${pools_1.DIAL[cor] ?? '33'} ${(0, utils_1.randint)(600, 799)} ${(0, utils_1.randint)(100000, 999999)}`,
86
+ date_of_birth: `${(0, utils_1.randint)(1962, 2003)}-${String((0, utils_1.randint)(1, 12)).padStart(2, '0')}-${String((0, utils_1.randint)(1, 28)).padStart(2, '0')}`,
87
+ nationality: (0, utils_1.pick)(pools_1.COUNTRIES),
88
+ country_of_residence: cor,
89
+ address_line1: `${(0, utils_1.pick)(pools_1.STREETS)} ${(0, utils_1.randint)(1, 180)}`,
90
+ address_line2: (0, utils_1.chance)(0.8) ? null : `Apt ${(0, utils_1.randint)(1, 40)}`,
91
+ city,
92
+ postal_code: postal,
93
+ country,
94
+ onboarding_status: onb,
95
+ risk_rating: risk,
96
+ is_pep: pep,
97
+ is_sanctioned: sanctioned,
98
+ referral_code: (0, utils_1.chance)(0.7) ? null : `REF${(0, utils_1.randint)(1000, 9999)}`,
99
+ created_at: (0, dates_1.daysAgo)(created),
100
+ updated_at: (0, dates_1.daysAgo)((0, utils_1.randint)(1, Math.max(2, created - 10))),
101
+ });
102
+ }
103
+ await (0, utils_1.insertAll)(knex, 'customers', customers);
104
+ return customers;
105
+ }
106
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlZWQvY3VzdG9tZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBdUJBLGdDQXFHQztBQXpIRCxtQ0FBa0M7QUFDbEMsbUNBU2lCO0FBQ2pCLG1DQUE0RTtBQUU1RSxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUM7QUFFZDs7OztHQUlHO0FBQ1ksS0FBSyxVQUFVLGFBQWEsQ0FBQyxJQUFVO0lBQ3BELE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxFQUFFO1FBQ2pELEtBQUssQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDakMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUMzQixLQUFLLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzFCLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdEIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0QixLQUFLLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQzVCLEtBQUssQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDNUIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1FBQ3JDLEtBQUssQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDOUIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUM5QixLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3JCLEtBQUssQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDNUIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN4QixLQUFLLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDLENB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
@@ -0,0 +1,7 @@
1
+ /** ISO timestamp `days` in the past (negative = future). */
2
+ export declare function daysAgo(days: number): string;
3
+ /** ISO timestamp `hours` in the past (negative = future). */
4
+ export declare function hoursAgo(hours: number): string;
5
+ /** `YYYY-MM-DD` date-only string `days` in the past (negative = future). */
6
+ export declare function dayOnlyAgo(days: number): string;
7
+ //# sourceMappingURL=dates.d.ts.map
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ // Demo dates are computed relative to the moment the data source is loaded, so a
3
+ // project bootstrapped with `forest create demo` always shows fresh, recent data
4
+ // — regardless of when it is run.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.daysAgo = daysAgo;
7
+ exports.hoursAgo = hoursAgo;
8
+ exports.dayOnlyAgo = dayOnlyAgo;
9
+ function shifted(days) {
10
+ const date = new Date();
11
+ date.setUTCDate(date.getUTCDate() - days);
12
+ return date;
13
+ }
14
+ /** ISO timestamp `days` in the past (negative = future). */
15
+ function daysAgo(days) {
16
+ return shifted(days).toISOString();
17
+ }
18
+ /** ISO timestamp `hours` in the past (negative = future). */
19
+ function hoursAgo(hours) {
20
+ const date = new Date();
21
+ date.setUTCHours(date.getUTCHours() - hours);
22
+ return date.toISOString();
23
+ }
24
+ /** `YYYY-MM-DD` date-only string `days` in the past (negative = future). */
25
+ function dayOnlyAgo(days) {
26
+ return shifted(days).toISOString().slice(0, 10);
27
+ }
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VlZC9kYXRlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsaUZBQWlGO0FBQ2pGLGlGQUFpRjtBQUNqRixrQ0FBa0M7O0FBVWxDLDBCQUVDO0FBR0QsNEJBS0M7QUFHRCxnQ0FFQztBQXZCRCxTQUFTLE9BQU8sQ0FBQyxJQUFZO0lBQzNCLE1BQU0sSUFBSSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7SUFDeEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFFMUMsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQsNERBQTREO0FBQzVELFNBQWdCLE9BQU8sQ0FBQyxJQUFZO0lBQ2xDLE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQ3JDLENBQUM7QUFFRCw2REFBNkQ7QUFDN0QsU0FBZ0IsUUFBUSxDQUFDLEtBQWE7SUFDcEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztJQUN4QixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsR0FBRyxLQUFLLENBQUMsQ0FBQztJQUU3QyxPQUFPLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztBQUM1QixDQUFDO0FBRUQsNEVBQTRFO0FBQzVFLFNBQWdCLFVBQVUsQ0FBQyxJQUFZO0lBQ3JDLE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDbEQsQ0FBQyJ9
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Populates a fresh SQLite database at `filename` with the demo fintech dataset.
3
+ *
4
+ * Tables are built in dependency order — customers first, then everything that
5
+ * references them — so foreign keys resolve and the data stays coherent. The
6
+ * caller owns the file's lifecycle; we own the connection.
7
+ */
8
+ export default function seed(filename: string): Promise<void>;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = seed;
7
+ const knex_1 = __importDefault(require("knex"));
8
+ const aml_1 = __importDefault(require("./aml"));
9
+ const cards_1 = __importDefault(require("./cards"));
10
+ const chargebacks_1 = __importDefault(require("./chargebacks"));
11
+ const customers_1 = __importDefault(require("./customers"));
12
+ const kyc_1 = __importDefault(require("./kyc"));
13
+ const refunds_1 = __importDefault(require("./refunds"));
14
+ /**
15
+ * Populates a fresh SQLite database at `filename` with the demo fintech dataset.
16
+ *
17
+ * Tables are built in dependency order — customers first, then everything that
18
+ * references them — so foreign keys resolve and the data stays coherent. The
19
+ * caller owns the file's lifecycle; we own the connection.
20
+ */
21
+ async function seed(filename) {
22
+ const knex = (0, knex_1.default)({
23
+ client: 'sqlite3',
24
+ connection: { filename },
25
+ useNullAsDefault: true,
26
+ });
27
+ try {
28
+ const customers = await (0, customers_1.default)(knex);
29
+ const { cardsByCust } = await (0, cards_1.default)(knex, customers);
30
+ const { refundsByCust } = await (0, refunds_1.default)(knex, customers);
31
+ await (0, kyc_1.default)(knex, customers);
32
+ await (0, aml_1.default)(knex, customers);
33
+ await (0, chargebacks_1.default)(knex, customers, cardsByCust, refundsByCust);
34
+ }
35
+ finally {
36
+ await knex.destroy();
37
+ }
38
+ }
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VlZC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQWdCQSx1QkFrQkM7QUFsQ0QsZ0RBQXdCO0FBRXhCLGdEQUE0QjtBQUM1QixvREFBZ0M7QUFDaEMsZ0VBQTRDO0FBQzVDLDREQUF3QztBQUN4QyxnREFBNEI7QUFDNUIsd0RBQW9DO0FBRXBDOzs7Ozs7R0FNRztBQUNZLEtBQUssVUFBVSxJQUFJLENBQUMsUUFBZ0I7SUFDakQsTUFBTSxJQUFJLEdBQUcsSUFBQSxjQUFJLEVBQUM7UUFDaEIsTUFBTSxFQUFFLFNBQVM7UUFDakIsVUFBVSxFQUFFLEVBQUUsUUFBUSxFQUFFO1FBQ3hCLGdCQUFnQixFQUFFLElBQUk7S0FDdkIsQ0FBQyxDQUFDO0lBRUgsSUFBSSxDQUFDO1FBQ0gsTUFBTSxTQUFTLEdBQUcsTUFBTSxJQUFBLG1CQUFhLEVBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUMsTUFBTSxFQUFFLFdBQVcsRUFBRSxHQUFHLE1BQU0sSUFBQSxlQUFTLEVBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQ3pELE1BQU0sRUFBRSxhQUFhLEVBQUUsR0FBRyxNQUFNLElBQUEsaUJBQVcsRUFBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFFN0QsTUFBTSxJQUFBLGFBQU8sRUFBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDL0IsTUFBTSxJQUFBLGFBQU8sRUFBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDL0IsTUFBTSxJQUFBLHFCQUFlLEVBQUMsSUFBSSxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsYUFBYSxDQUFDLENBQUM7SUFDckUsQ0FBQztZQUFTLENBQUM7UUFDVCxNQUFNLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUN2QixDQUFDO0FBQ0gsQ0FBQyJ9
@@ -0,0 +1,9 @@
1
+ import type { Customer } from './types';
2
+ import type { Knex } from 'knex';
3
+ /**
4
+ * Opens KYC cases (1–2 per customer) plus their documents. Case status mirrors the
5
+ * customer's compliance profile: sanctioned/PEP customers escalate, approved ones
6
+ * tend to resolve cleanly.
7
+ */
8
+ export default function seedKyc(knex: Knex, customers: Customer[]): Promise<void>;
9
+ //# sourceMappingURL=kyc.d.ts.map