@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
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # @forestadmin/datasource-demo-fintech
2
+
3
+ Demo data source for Forest Admin, themed around a fintech / compliance back
4
+ office (customers, cards, KYC, AML alerts, chargebacks…).
5
+
6
+ On boot it generates a throwaway SQLite database with [faker](https://fakerjs.dev/),
7
+ seeds it via [Knex](https://knexjs.org/), and exposes it through
8
+ `@forestadmin/datasource-sql`. The schema, column types and primary keys are
9
+ introspected from the freshly-created tables. It is used by `forest create demo`
10
+ to bootstrap a project with realistic sample data.
11
+
12
+ ```ts
13
+ import { createDemoFintechDataSource } from '@forestadmin/datasource-demo-fintech';
14
+
15
+ agent.addDataSource(createDemoFintechDataSource());
16
+ ```
17
+
18
+ ## How the data is built
19
+
20
+ A fresh database is generated on every boot (no fixed seed → the dataset is
21
+ re-rolled each time), under the OS temp directory. The seed lives in `src/seed`:
22
+
23
+ - `seed/index.ts` — orchestrates the builders in dependency order (customers
24
+ first, then everything that references them) and owns the Knex connection.
25
+ - one file per domain (`customers`, `cards`, `kyc`, `aml`, `refunds`,
26
+ `chargebacks`) — each creates its table(s) and inserts rows.
27
+ - `pools.ts` / `utils.ts` — curated reference data (kept hand-written so
28
+ geography stays internally consistent) and faker-backed random helpers.
29
+
30
+ Business coherence is enforced in the builders, not by faker: sanctioned
31
+ customers never clear onboarding, alerts are weighted by customer risk, a filed
32
+ SAR escalates its source alert, chargebacks link back to the right card and
33
+ refund request, etc.
34
+
35
+ Relations, Smart Actions, segments and computed fields are layered on top in
36
+ `src/customizations/*`. Dates use the relative `daysAgo(n)` / `dayOnlyAgo(n)`
37
+ helpers (see `src/dates.ts`) so the demo always shows recent data.
38
+
39
+ To rescale the dataset, edit the population sizes in the relevant `src/seed/*`
40
+ builder (e.g. `N` in `seed/customers.ts`).
@@ -0,0 +1,3 @@
1
+ import type { CollectionCustomizer, TSchema } from '@forestadmin/datasource-customizer';
2
+ export default function customizeAmlAlerts(collection: CollectionCustomizer<TSchema, 'aml_alerts'>): void;
3
+ //# sourceMappingURL=aml_alerts.d.ts.map
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = customizeAmlAlerts;
4
+ const utils_1 = require("./utils");
5
+ function customizeAmlAlerts(collection) {
6
+ // Relationships
7
+ collection
8
+ .addManyToOneRelation('customer', 'customers', { foreignKey: 'customer_id' })
9
+ .addOneToManyRelation('sarReports', 'sar_reports', { originKey: 'alert_id' });
10
+ collection.addAction('Clear Alert (False Positive)', {
11
+ scope: 'Single',
12
+ form: [
13
+ {
14
+ label: 'Resolution Notes',
15
+ type: 'String',
16
+ isRequired: true,
17
+ description: 'Explain why this alert is considered a false positive.',
18
+ },
19
+ ],
20
+ execute: async (context, resultBuilder) => {
21
+ const id = await context.getRecordId();
22
+ await context.collection.update((0, utils_1.byId)(id), {
23
+ status: 'CLEARED',
24
+ resolution_notes: context.formValues['Resolution Notes'],
25
+ resolved_at: (0, utils_1.now)(),
26
+ });
27
+ return resultBuilder.success('Alert cleared as false positive. No SAR filed.');
28
+ },
29
+ });
30
+ collection.addAction('Create SAR', {
31
+ scope: 'Single',
32
+ form: [
33
+ {
34
+ label: 'Narrative',
35
+ type: 'String',
36
+ isRequired: true,
37
+ description: 'Describe the suspicious activity (Part V of the SAR).',
38
+ },
39
+ { label: 'Activity Start Date', type: 'Dateonly', isRequired: true },
40
+ { label: 'Activity End Date', type: 'Dateonly', isRequired: true },
41
+ { label: 'Total Amount (€)', type: 'Number', isRequired: true },
42
+ { label: 'Transaction Count', type: 'Number', isRequired: false },
43
+ ],
44
+ execute: async (context, resultBuilder) => {
45
+ const alertId = await context.getRecordId();
46
+ const alert = await context.getRecord(['alert_type', 'customer_id']);
47
+ const sarReports = context.dataSource.getCollection('sar_reports');
48
+ const existing = await sarReports.list({ conditionTree: { field: 'alert_id', operator: 'Equal', value: alertId } }, ['reference']);
49
+ if (existing.length) {
50
+ return resultBuilder.error(`A SAR already exists for this alert (${existing[0].reference}). File it from the SAR Reports collection.`);
51
+ }
52
+ const all = await sarReports.list({}, ['id']);
53
+ const nextId = all.reduce((max, r) => Math.max(max, Number(r.id)), 0) + 1;
54
+ const reference = `SAR-${new Date().getUTCFullYear()}-${String(nextId).padStart(5, '0')}`;
55
+ await sarReports.create([
56
+ {
57
+ id: nextId,
58
+ alert_id: alertId,
59
+ customer_id: alert.customer_id,
60
+ reference,
61
+ status: 'DRAFT',
62
+ activity_type: alert.alert_type,
63
+ activity_start_date: context.formValues['Activity Start Date'],
64
+ activity_end_date: context.formValues['Activity End Date'],
65
+ total_amount: context.formValues['Total Amount (€)'],
66
+ transaction_count: context.formValues['Transaction Count'] ?? null,
67
+ narrative: context.formValues.Narrative,
68
+ created_at: (0, utils_1.now)(),
69
+ },
70
+ ]);
71
+ await context.collection.update((0, utils_1.byId)(alertId), { status: 'ESCALATED' });
72
+ return resultBuilder.success(`SAR draft created (${reference}). Alert escalated for MLRO review.`);
73
+ },
74
+ });
75
+ collection.addAction('Escalate to Compliance', {
76
+ scope: 'Single',
77
+ form: [
78
+ {
79
+ label: 'Escalation Reason',
80
+ type: 'String',
81
+ isRequired: true,
82
+ description: 'Explain why this alert requires senior compliance review (MLRO).',
83
+ },
84
+ ],
85
+ execute: async (context, resultBuilder) => {
86
+ const id = await context.getRecordId();
87
+ await context.collection.update((0, utils_1.byId)(id), {
88
+ status: 'ESCALATED',
89
+ severity: 'HIGH',
90
+ resolution_notes: context.formValues['Escalation Reason'],
91
+ });
92
+ return resultBuilder.success('Alert escalated to compliance (MLRO). Severity upgraded to HIGH.');
93
+ },
94
+ });
95
+ collection.addAction('File SAR', {
96
+ scope: 'Single',
97
+ form: [
98
+ {
99
+ label: 'SAR Reference',
100
+ type: 'String',
101
+ isRequired: true,
102
+ description: 'Internal SAR case number (e.g. SAR-2026-00042).',
103
+ },
104
+ ],
105
+ execute: async (context, resultBuilder) => {
106
+ const id = await context.getRecordId();
107
+ await context.collection.update((0, utils_1.byId)(id), {
108
+ status: 'SAR_FILED',
109
+ sar_reference: context.formValues['SAR Reference'],
110
+ resolved_at: (0, utils_1.now)(),
111
+ });
112
+ return resultBuilder.success(`SAR filed (ref: ${context.formValues['SAR Reference']}).`);
113
+ },
114
+ });
115
+ collection.addAction('Request Enhanced Due Diligence', {
116
+ scope: 'Single',
117
+ form: [
118
+ {
119
+ label: 'EDD Reason',
120
+ type: 'String',
121
+ isRequired: true,
122
+ description: 'Explain why enhanced due diligence is required for this customer.',
123
+ },
124
+ ],
125
+ execute: async (context, resultBuilder) => {
126
+ const id = await context.getRecordId();
127
+ // Alert stays OPEN — investigation is ongoing, EDD requested.
128
+ await context.collection.update((0, utils_1.byId)(id), {
129
+ resolution_notes: `EDD requested: ${context.formValues['EDD Reason']}`,
130
+ });
131
+ return resultBuilder.success('Enhanced Due Diligence requested. Customer flagged for monitoring.');
132
+ },
133
+ });
134
+ }
135
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW1sX2FsZXJ0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jdXN0b21pemF0aW9ucy9hbWxfYWxlcnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBSUEscUNBaUtDO0FBbktELG1DQUFvQztBQUVwQyxTQUF3QixrQkFBa0IsQ0FDeEMsVUFBdUQ7SUFFdkQsZ0JBQWdCO0lBQ2hCLFVBQVU7U0FDUCxvQkFBb0IsQ0FBQyxVQUFVLEVBQUUsV0FBVyxFQUFFLEVBQUUsVUFBVSxFQUFFLGFBQWEsRUFBRSxDQUFDO1NBQzVFLG9CQUFvQixDQUFDLFlBQVksRUFBRSxhQUFhLEVBQUUsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUVoRixVQUFVLENBQUMsU0FBUyxDQUFDLDhCQUE4QixFQUFFO1FBQ25ELEtBQUssRUFBRSxRQUFRO1FBQ2YsSUFBSSxFQUFFO1lBQ0o7Z0JBQ0UsS0FBSyxFQUFFLGtCQUFrQjtnQkFDekIsSUFBSSxFQUFFLFFBQVE7Z0JBQ2QsVUFBVSxFQUFFLElBQUk7Z0JBQ2hCLFdBQVcsRUFBRSx3REFBd0Q7YUFDdEU7U0FDRjtRQUNELE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLGFBQWEsRUFBRSxFQUFFO1lBQ3hDLE1BQU0sRUFBRSxHQUFHLE1BQU0sT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBRXZDLE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBQSxZQUFJLEVBQUMsRUFBRSxDQUFDLEVBQUU7Z0JBQ3hDLE1BQU0sRUFBRSxTQUFTO2dCQUNqQixnQkFBZ0IsRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDLGtCQUFrQixDQUFDO2dCQUN4RCxXQUFXLEVBQUUsSUFBQSxXQUFHLEdBQUU7YUFDbkIsQ0FBQyxDQUFDO1lBRUgsT0FBTyxhQUFhLENBQUMsT0FBTyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7UUFDakYsQ0FBQztLQUNGLENBQUMsQ0FBQztJQUVI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
@@ -0,0 +1,3 @@
1
+ import type { CollectionCustomizer, TSchema } from '@forestadmin/datasource-customizer';
2
+ export default function customizeCards(collection: CollectionCustomizer<TSchema, 'cards'>): void;
3
+ //# sourceMappingURL=cards.d.ts.map
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = customizeCards;
4
+ const utils_1 = require("./utils");
5
+ function customizeCards(collection) {
6
+ // Relationships
7
+ collection
8
+ .addManyToOneRelation('customer', 'customers', { foreignKey: 'customer_id' })
9
+ .addOneToManyRelation('chargebacks', 'chargebacks', { originKey: 'card_id' });
10
+ // Block one or more cards (bulk).
11
+ collection.addAction('Block Card', {
12
+ scope: 'Bulk',
13
+ form: [
14
+ {
15
+ label: 'Info',
16
+ type: 'String',
17
+ isReadOnly: true,
18
+ isRequired: false,
19
+ value: async (context) => {
20
+ const count = await context.collection.aggregate(context.filter, { operation: 'Count' });
21
+ return `This action will block ${count[0]?.value ?? 0} card(s).`;
22
+ },
23
+ },
24
+ {
25
+ label: 'Block Reason',
26
+ type: 'Enum',
27
+ enumValues: ['LOST', 'STOLEN', 'FRAUD', 'AML_FREEZE', 'CUSTOMER_REQUEST'],
28
+ isRequired: true,
29
+ },
30
+ ],
31
+ execute: async (context, resultBuilder) => {
32
+ const ids = await context.getRecordIds();
33
+ const reason = context.formValues['Block Reason'];
34
+ await context.collection.update((0, utils_1.byIds)(ids), {
35
+ status: 'BLOCKED',
36
+ blocked_reason: reason,
37
+ blocked_at: (0, utils_1.now)(),
38
+ });
39
+ return resultBuilder.success(`${ids.length} card(s) blocked (${reason}).`);
40
+ },
41
+ });
42
+ // Unblock one or more cards (bulk).
43
+ collection.addAction('Unblock Card', {
44
+ scope: 'Bulk',
45
+ form: [
46
+ {
47
+ label: 'Info',
48
+ type: 'String',
49
+ isReadOnly: true,
50
+ isRequired: false,
51
+ value: async (context) => {
52
+ const count = await context.collection.aggregate(context.filter, { operation: 'Count' });
53
+ return `This action will unblock ${count[0]?.value ?? 0} card(s).`;
54
+ },
55
+ },
56
+ { label: 'Unblock Reason', type: 'String', isRequired: false },
57
+ ],
58
+ execute: async (context, resultBuilder) => {
59
+ const ids = await context.getRecordIds();
60
+ await context.collection.update((0, utils_1.byIds)(ids), {
61
+ status: 'ACTIVE',
62
+ blocked_reason: null,
63
+ blocked_at: null,
64
+ });
65
+ return resultBuilder.success(`${ids.length} card(s) reactivated.`);
66
+ },
67
+ });
68
+ // Cancel a card and issue a fresh one for the same account.
69
+ collection.addAction('Replace Card', {
70
+ scope: 'Single',
71
+ execute: async (context, resultBuilder) => {
72
+ const id = await context.getRecordId();
73
+ const card = await context.getRecord(['customer_id', 'card_type', 'status']);
74
+ await context.collection.update((0, utils_1.byId)(id), { status: 'CANCELLED' });
75
+ const lastFour = String(Math.floor(1000 + Math.random() * 9000));
76
+ const expiry = new Date();
77
+ expiry.setUTCFullYear(expiry.getUTCFullYear() + 3);
78
+ // id is auto-assigned by the in-memory collection when omitted.
79
+ await context.collection.create([
80
+ {
81
+ customer_id: card.customer_id,
82
+ card_type: card.card_type,
83
+ status: 'ACTIVE',
84
+ last_four_digits: lastFour,
85
+ issued_at: (0, utils_1.now)(),
86
+ expires_at: expiry.toISOString().slice(0, 10),
87
+ blocked_reason: null,
88
+ blocked_at: null,
89
+ },
90
+ ]);
91
+ return resultBuilder.success(`Old card cancelled. Replacement ••${lastFour} issued — arrives in 3–5 business days.`);
92
+ },
93
+ });
94
+ }
95
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FyZHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY3VzdG9taXphdGlvbnMvY2FyZHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFJQSxpQ0F3R0M7QUExR0QsbUNBQTJDO0FBRTNDLFNBQXdCLGNBQWMsQ0FBQyxVQUFrRDtJQUN2RixnQkFBZ0I7SUFDaEIsVUFBVTtTQUNQLG9CQUFvQixDQUFDLFVBQVUsRUFBRSxXQUFXLEVBQUUsRUFBRSxVQUFVLEVBQUUsYUFBYSxFQUFFLENBQUM7U0FDNUUsb0JBQW9CLENBQUMsYUFBYSxFQUFFLGFBQWEsRUFBRSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO0lBRWhGLGtDQUFrQztJQUNsQyxVQUFVLENBQUMsU0FBUyxDQUFDLFlBQVksRUFBRTtRQUNqQyxLQUFLLEVBQUUsTUFBTTtRQUNiLElBQUksRUFBRTtZQUNKO2dCQUNFLEtBQUssRUFBRSxNQUFNO2dCQUNiLElBQUksRUFBRSxRQUFRO2dCQUNkLFVBQVUsRUFBRSxJQUFJO2dCQUNoQixVQUFVLEVBQUUsS0FBSztnQkFDakIsS0FBSyxFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtvQkFDckIsTUFBTSxLQUFLLEdBQUcsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7b0JBRXpGLE9BQU8sMEJBQTBCLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLElBQUksQ0FBQyxXQUFXLENBQUM7Z0JBQ25FLENBQUM7YUFDRjtZQUNEO2dCQUNFLEtBQUssRUFBRSxjQUFjO2dCQUNyQixJQUFJLEVBQUUsTUFBTTtnQkFDWixVQUFVLEVBQUUsQ0FBQyxNQUFNLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsa0JBQWtCLENBQUM7Z0JBQ3pFLFVBQVUsRUFBRSxJQUFJO2FBQ2pC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
@@ -0,0 +1,3 @@
1
+ import type { CollectionCustomizer, TSchema } from '@forestadmin/datasource-customizer';
2
+ export default function customizeChargebacks(collection: CollectionCustomizer<TSchema, 'chargebacks'>): void;
3
+ //# sourceMappingURL=chargebacks.d.ts.map
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = customizeChargebacks;
4
+ const utils_1 = require("./utils");
5
+ function customizeChargebacks(collection) {
6
+ // Relationships
7
+ collection
8
+ .addManyToOneRelation('customer', 'customers', { foreignKey: 'customer_id' })
9
+ .addManyToOneRelation('card', 'cards', { foreignKey: 'card_id' })
10
+ .addManyToOneRelation('refundRequest', 'refund_requests', { foreignKey: 'refund_request_id' });
11
+ // Computed fields
12
+ collection.addField('days_to_deadline', {
13
+ columnType: 'Number',
14
+ dependencies: ['representment_deadline', 'status'],
15
+ getValues: records => records.map(r => {
16
+ if (!r.representment_deadline)
17
+ return null;
18
+ if (utils_1.RESOLVED_CHARGEBACK_STATUSES.includes(r.status))
19
+ return null;
20
+ const diffMs = new Date(r.representment_deadline).getTime() - Date.now();
21
+ return Math.ceil(diffMs / (1000 * 60 * 60 * 24));
22
+ }),
23
+ });
24
+ collection.addField('is_overdue', {
25
+ columnType: 'Boolean',
26
+ dependencies: ['representment_deadline', 'status'],
27
+ getValues: records => records.map(r => {
28
+ if (!r.representment_deadline)
29
+ return false;
30
+ if (utils_1.RESOLVED_CHARGEBACK_STATUSES.includes(r.status))
31
+ return false;
32
+ return new Date(r.representment_deadline).getTime() < Date.now();
33
+ }),
34
+ });
35
+ // Segments
36
+ collection.addSegment('Open', () => ({
37
+ field: 'status',
38
+ operator: 'NotIn',
39
+ value: utils_1.RESOLVED_CHARGEBACK_STATUSES,
40
+ }));
41
+ collection.addSegment('Overdue', () => ({
42
+ aggregator: 'And',
43
+ conditions: [
44
+ { field: 'status', operator: 'NotIn', value: utils_1.RESOLVED_CHARGEBACK_STATUSES },
45
+ { field: 'representment_deadline', operator: 'Before', value: (0, utils_1.now)() },
46
+ ],
47
+ }));
48
+ collection.addSegment('Awaiting evidence', () => ({
49
+ aggregator: 'And',
50
+ conditions: [
51
+ { field: 'status', operator: 'Equal', value: 'PRESENTED' },
52
+ { field: 'evidence_submitted_at', operator: 'Missing' },
53
+ ],
54
+ }));
55
+ collection.addSegment('Pre-arbitration & Arbitration', () => ({
56
+ field: 'status',
57
+ operator: 'In',
58
+ value: ['PRE_ARBITRATION', 'ARBITRATION'],
59
+ }));
60
+ // ── Actions ────────────────────────────────────────────────────────────────
61
+ collection.addAction('File with Network', {
62
+ scope: 'Single',
63
+ form: [
64
+ {
65
+ label: 'Evidence URL',
66
+ type: 'String',
67
+ isRequired: true,
68
+ description: 'Link to the evidence bundle submitted to the network (transaction logs, device fingerprint, cardholder statement, etc.).',
69
+ },
70
+ {
71
+ label: 'Analyst Notes',
72
+ type: 'String',
73
+ description: 'Internal notes — not transmitted to the network. Visible only to the ops team.',
74
+ },
75
+ ],
76
+ execute: async (context, resultBuilder) => {
77
+ const id = await context.getRecordId();
78
+ const record = await context.getRecord(['status', 'network', 'reason_code']);
79
+ if (record.status !== 'INITIATED') {
80
+ return resultBuilder.error(`Cannot file: chargeback is in status ${record.status}. Only INITIATED chargebacks can be filed.`);
81
+ }
82
+ const deadline = new Date();
83
+ deadline.setUTCDate(deadline.getUTCDate() + 45); // Visa/MC representment window
84
+ await context.collection.update((0, utils_1.byId)(id), {
85
+ status: 'PRESENTED',
86
+ evidence_url: context.formValues['Evidence URL'],
87
+ evidence_submitted_at: (0, utils_1.now)(),
88
+ representment_deadline: deadline.toISOString(),
89
+ analyst_email: context.caller.email,
90
+ updated_at: (0, utils_1.now)(),
91
+ });
92
+ return resultBuilder.success(`Filed with ${record.network} (${record.reason_code}). Deadline ${deadline
93
+ .toISOString()
94
+ .slice(0, 10)}.`);
95
+ },
96
+ });
97
+ collection.addAction('Request Cardholder Info', {
98
+ scope: 'Single',
99
+ form: [
100
+ {
101
+ label: 'Information Requested',
102
+ type: 'String',
103
+ isRequired: true,
104
+ description: 'What do you need from the cardholder? (e.g. proof of purchase, police report reference, screenshots of merchant communication)',
105
+ },
106
+ {
107
+ label: 'Reply Deadline (days)',
108
+ type: 'Enum',
109
+ enumValues: ['3', '5', '7', '14'],
110
+ isRequired: true,
111
+ description: 'How long does the cardholder have to respond?',
112
+ },
113
+ ],
114
+ execute: async (context, resultBuilder) => {
115
+ const id = await context.getRecordId();
116
+ const record = await context.getRecord(['status', 'resolution_notes']);
117
+ if (utils_1.RESOLVED_CHARGEBACK_STATUSES.includes(record.status)) {
118
+ return resultBuilder.error(`Cannot send RFI: chargeback already resolved (${record.status}).`);
119
+ }
120
+ const days = parseInt(context.formValues['Reply Deadline (days)'], 10);
121
+ const replyBy = new Date(Date.now() + days * 86400000).toISOString().slice(0, 10);
122
+ const entry = `[RFI ${(0, utils_1.now)().slice(0, 10)} by ${context.caller.email}] Requested: "${context.formValues['Information Requested']}" — reply by ${replyBy}`;
123
+ const newNotes = record.resolution_notes ? `${record.resolution_notes}\n${entry}` : entry;
124
+ await context.collection.update((0, utils_1.byId)(id), {
125
+ resolution_notes: newNotes,
126
+ analyst_email: context.caller.email,
127
+ updated_at: (0, utils_1.now)(),
128
+ });
129
+ return resultBuilder.success(`RFI sent to cardholder. Reply expected by ${replyBy}.`);
130
+ },
131
+ });
132
+ collection.addAction('Block Linked Card', {
133
+ scope: 'Single',
134
+ form: [
135
+ {
136
+ label: 'Block Reason',
137
+ type: 'Enum',
138
+ enumValues: ['FRAUD', 'STOLEN', 'LOST', 'AML_FREEZE', 'CUSTOMER_REQUEST'],
139
+ isRequired: true,
140
+ },
141
+ ],
142
+ execute: async (context, resultBuilder) => {
143
+ const card = await context.getRecord([
144
+ 'card_id',
145
+ 'card:status',
146
+ 'card:last_four_digits',
147
+ 'card:card_type',
148
+ ]);
149
+ if (!card.card_id)
150
+ return resultBuilder.error('No card linked to this chargeback.');
151
+ if (card.card?.status === 'BLOCKED') {
152
+ return resultBuilder.error(`Card ••${card.card.last_four_digits} is already blocked.`);
153
+ }
154
+ await context.dataSource.getCollection('cards').update({ conditionTree: { field: 'id', operator: 'Equal', value: card.card_id } }, {
155
+ status: 'BLOCKED',
156
+ blocked_reason: `${context.formValues['Block Reason']} — from chargeback investigation by ${context.caller.email}`,
157
+ blocked_at: (0, utils_1.now)(),
158
+ });
159
+ return resultBuilder.success(`${card.card?.card_type} card ••${card.card?.last_four_digits} blocked (${context.formValues['Block Reason']}).`);
160
+ },
161
+ });
162
+ collection.addAction('Accept Liability & Refund Customer', {
163
+ scope: 'Single',
164
+ form: [
165
+ {
166
+ label: 'Reason',
167
+ type: 'String',
168
+ isRequired: true,
169
+ description: 'Why are we accepting liability without contesting?',
170
+ },
171
+ ],
172
+ execute: async (context, resultBuilder) => {
173
+ const id = await context.getRecordId();
174
+ const record = await context.getRecord(['status', 'amount', 'currency']);
175
+ if (utils_1.RESOLVED_CHARGEBACK_STATUSES.includes(record.status)) {
176
+ return resultBuilder.error(`Chargeback already resolved (${record.status}).`);
177
+ }
178
+ await context.collection.update((0, utils_1.byId)(id), {
179
+ status: 'ACCEPTED',
180
+ decision_at: (0, utils_1.now)(),
181
+ provisional_credit_issued: true,
182
+ resolution_notes: context.formValues.Reason,
183
+ analyst_email: context.caller.email,
184
+ updated_at: (0, utils_1.now)(),
185
+ });
186
+ return resultBuilder.success(`Liability accepted. Credit of ${record.amount} ${record.currency} queued for the customer.`);
187
+ },
188
+ });
189
+ collection.addAction('Mark Won', {
190
+ scope: 'Single',
191
+ form: [{ label: 'Resolution Notes', type: 'String', description: 'Network decision summary.' }],
192
+ execute: async (context, resultBuilder) => {
193
+ const id = await context.getRecordId();
194
+ const record = await context.getRecord(['status', 'amount', 'currency']);
195
+ if (utils_1.RESOLVED_CHARGEBACK_STATUSES.includes(record.status)) {
196
+ return resultBuilder.error(`Chargeback already resolved (${record.status}).`);
197
+ }
198
+ await context.collection.update((0, utils_1.byId)(id), {
199
+ status: 'WON',
200
+ decision_at: (0, utils_1.now)(),
201
+ provisional_credit_issued: true,
202
+ resolution_notes: context.formValues['Resolution Notes'] ?? null,
203
+ analyst_email: context.caller.email,
204
+ updated_at: (0, utils_1.now)(),
205
+ });
206
+ return resultBuilder.success(`Chargeback won. Final credit of ${record.amount} ${record.currency} posted.`);
207
+ },
208
+ });
209
+ collection.addAction('Mark Lost', {
210
+ scope: 'Single',
211
+ form: [
212
+ {
213
+ label: 'Resolution Notes',
214
+ type: 'String',
215
+ isRequired: true,
216
+ description: 'Why did we lose? Network ruling, evidence rejected, etc.',
217
+ },
218
+ ],
219
+ execute: async (context, resultBuilder) => {
220
+ const id = await context.getRecordId();
221
+ const record = await context.getRecord(['status']);
222
+ if (utils_1.RESOLVED_CHARGEBACK_STATUSES.includes(record.status)) {
223
+ return resultBuilder.error(`Chargeback already resolved (${record.status}).`);
224
+ }
225
+ await context.collection.update((0, utils_1.byId)(id), {
226
+ status: 'LOST',
227
+ decision_at: (0, utils_1.now)(),
228
+ provisional_credit_issued: false,
229
+ resolution_notes: context.formValues['Resolution Notes'],
230
+ analyst_email: context.caller.email,
231
+ updated_at: (0, utils_1.now)(),
232
+ });
233
+ return resultBuilder.success('Chargeback marked as lost. No credit issued.');
234
+ },
235
+ });
236
+ collection.addAction('Dismiss Dispute', {
237
+ scope: 'Single',
238
+ form: [
239
+ {
240
+ label: 'Dismissal Reason',
241
+ type: 'Enum',
242
+ enumValues: [
243
+ 'BEYOND_FILING_WINDOW',
244
+ 'INSUFFICIENT_EVIDENCE',
245
+ 'CARDHOLDER_WITHDREW',
246
+ 'NOT_A_VALID_DISPUTE',
247
+ 'OTHER',
248
+ ],
249
+ isRequired: true,
250
+ },
251
+ { label: 'Notes', type: 'String', isRequired: true, description: 'Internal notes.' },
252
+ ],
253
+ execute: async (context, resultBuilder) => {
254
+ const id = await context.getRecordId();
255
+ const record = await context.getRecord(['status']);
256
+ if (utils_1.RESOLVED_CHARGEBACK_STATUSES.includes(record.status)) {
257
+ return resultBuilder.error(`Chargeback is already resolved (${record.status}).`);
258
+ }
259
+ await context.collection.update((0, utils_1.byId)(id), {
260
+ status: 'DISMISSED',
261
+ decision_at: (0, utils_1.now)(),
262
+ provisional_credit_issued: false,
263
+ resolution_notes: `[${context.formValues['Dismissal Reason']}] ${context.formValues.Notes}`,
264
+ analyst_email: context.caller.email,
265
+ updated_at: (0, utils_1.now)(),
266
+ });
267
+ return resultBuilder.success(`Dispute dismissed (${context.formValues['Dismissal Reason']}). No refund issued.`);
268
+ },
269
+ });
270
+ }
271
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcmdlYmFja3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY3VzdG9taXphdGlvbnMvY2hhcmdlYmFja3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFJQSx1Q0FxVUM7QUF2VUQsbUNBQThFO0FBRTlFLFNBQXdCLG9CQUFvQixDQUMxQyxVQUF3RDtJQUV4RCxnQkFBZ0I7SUFDaEIsVUFBVTtTQUNQLG9CQUFvQixDQUFDLFVBQVUsRUFBRSxXQUFXLEVBQUUsRUFBRSxVQUFVLEVBQUUsYUFBYSxFQUFFLENBQUM7U0FDNUUsb0JBQW9CLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsQ0FBQztTQUNoRSxvQkFBb0IsQ0FBQyxlQUFlLEVBQUUsaUJBQWlCLEVBQUUsRUFBRSxVQUFVLEVBQUUsbUJBQW1CLEVBQUUsQ0FBQyxDQUFDO0lBRWpHLGtCQUFrQjtJQUNsQixVQUFVLENBQUMsUUFBUSxDQUFDLGtCQUFrQixFQUFFO1FBQ3RDLFVBQVUsRUFBRSxRQUFRO1FBQ3BCLFlBQVksRUFBRSxDQUFDLHdCQUF3QixFQUFFLFFBQVEsQ0FBQztRQUNsRCxTQUFTLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FDbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRTtZQUNkLElBQUksQ0FBQyxDQUFDLENBQUMsc0JBQXNCO2dCQUFFLE9BQU8sSUFBSSxDQUFDO1lBQzNDLElBQUksb0NBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQWdCLENBQUM7Z0JBQUUsT0FBTyxJQUFJLENBQUM7WUFDdkQsTUFBTSxNQUFNLEdBQUcsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLHNCQUFnQyxDQUFDLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBRW5GLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLEdBQUcsRUFB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
@@ -0,0 +1,3 @@
1
+ import type { CollectionCustomizer, TSchema } from '@forestadmin/datasource-customizer';
2
+ export default function customizeCustomers(collection: CollectionCustomizer<TSchema, 'customers'>): void;
3
+ //# sourceMappingURL=customers.d.ts.map
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = customizeCustomers;
4
+ // customers is the hub: everything links back to a customer.
5
+ function customizeCustomers(collection) {
6
+ collection
7
+ .addOneToManyRelation('cards', 'cards', { originKey: 'customer_id' })
8
+ .addOneToManyRelation('amlAlerts', 'aml_alerts', { originKey: 'customer_id' })
9
+ .addOneToManyRelation('kycCases', 'kyc_cases', { originKey: 'customer_id' })
10
+ .addOneToManyRelation('kycDocuments', 'kyc_documents', { originKey: 'customer_id' })
11
+ .addOneToManyRelation('chargebacks', 'chargebacks', { originKey: 'customer_id' })
12
+ .addOneToManyRelation('refundRequests', 'refund_requests', { originKey: 'customer_id' })
13
+ .addOneToManyRelation('sarReports', 'sar_reports', { originKey: 'customer_id' });
14
+ }
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2N1c3RvbWl6YXRpb25zL2N1c3RvbWVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUdBLHFDQVdDO0FBWkQsNkRBQTZEO0FBQzdELFNBQXdCLGtCQUFrQixDQUN4QyxVQUFzRDtJQUV0RCxVQUFVO1NBQ1Asb0JBQW9CLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxFQUFFLFNBQVMsRUFBRSxhQUFhLEVBQUUsQ0FBQztTQUNwRSxvQkFBb0IsQ0FBQyxXQUFXLEVBQUUsWUFBWSxFQUFFLEVBQUUsU0FBUyxFQUFFLGFBQWEsRUFBRSxDQUFDO1NBQzdFLG9CQUFvQixDQUFDLFVBQVUsRUFBRSxXQUFXLEVBQUUsRUFBRSxTQUFTLEVBQUUsYUFBYSxFQUFFLENBQUM7U0FDM0Usb0JBQW9CLENBQUMsY0FBYyxFQUFFLGVBQWUsRUFBRSxFQUFFLFNBQVMsRUFBRSxhQUFhLEVBQUUsQ0FBQztTQUNuRixvQkFBb0IsQ0FBQyxhQUFhLEVBQUUsYUFBYSxFQUFFLEVBQUUsU0FBUyxFQUFFLGFBQWEsRUFBRSxDQUFDO1NBQ2hGLG9CQUFvQixDQUFDLGdCQUFnQixFQUFFLGlCQUFpQixFQUFFLEVBQUUsU0FBUyxFQUFFLGFBQWEsRUFBRSxDQUFDO1NBQ3ZGLG9CQUFvQixDQUFDLFlBQVksRUFBRSxhQUFhLEVBQUUsRUFBRSxTQUFTLEVBQUUsYUFBYSxFQUFFLENBQUMsQ0FBQztBQUNyRixDQUFDIn0=
@@ -0,0 +1,3 @@
1
+ import type { CollectionCustomizer, TSchema } from '@forestadmin/datasource-customizer';
2
+ export default function customizeKycCases(collection: CollectionCustomizer<TSchema, 'kyc_cases'>): void;
3
+ //# sourceMappingURL=kyc_cases.d.ts.map