@fonderie/customers 1.0.0 → 1.1.1

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.
@@ -0,0 +1,189 @@
1
+ <!-- GENERATED — do not edit. Regenerate with: npm run docs:signatures -->
2
+
3
+ # @fonderie/customers — outcomes
4
+
5
+ What this package does to a running app: tables its migrations create,
6
+ rows it seeds, routes it registers. Generated from the migration SQL and
7
+ route tables in source — trust this file instead of reading `dist/` or
8
+ downloading tarballs.
9
+
10
+ ## Database tables (after all migrations)
11
+
12
+ ### `fonderie_addresses`
13
+
14
+ ```sql
15
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid()
16
+ country_iso TEXT NOT NULL
17
+ subdivision1_iso TEXT
18
+ subdivision2_iso TEXT
19
+ zip_postal_code TEXT NOT NULL
20
+ line1 TEXT
21
+ line2 TEXT
22
+ unit TEXT
23
+ ```
24
+
25
+ ### `fonderie_customer_addresses`
26
+
27
+ ```sql
28
+ addr_id UUID NOT NULL REFERENCES fonderie_addresses(id) ON DELETE CASCADE
29
+ customer_id UUID NOT NULL REFERENCES fonderie_customers(id) ON DELETE CASCADE
30
+ label TEXT NOT NULL DEFAULT 'service'
31
+ is_primary BOOLEAN NOT NULL DEFAULT false
32
+ label_id UUID REFERENCES fonderie_customer_labels(id)
33
+ CONSTRAINT fonderie_customer_addresses_label_id_fkey FOREIGN KEY (label_id) REFERENCES fonderie_customer_labels(id) ON DELETE SET NULL
34
+ -- PRIMARY KEY (addr_id, customer_id)
35
+ ```
36
+
37
+ ### `fonderie_customer_emails`
38
+
39
+ ```sql
40
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid()
41
+ customer_id UUID NOT NULL REFERENCES fonderie_customers(id) ON DELETE CASCADE
42
+ email TEXT NOT NULL
43
+ label TEXT NOT NULL DEFAULT 'work'
44
+ is_primary BOOLEAN NOT NULL DEFAULT false
45
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
46
+ label_id UUID REFERENCES fonderie_customer_labels(id)
47
+ CONSTRAINT fonderie_customer_emails_label_id_fkey FOREIGN KEY (label_id) REFERENCES fonderie_customer_labels(id) ON DELETE SET NULL
48
+ ```
49
+
50
+ ### `fonderie_customer_labels`
51
+
52
+ ```sql
53
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid()
54
+ type fonderie_customer_label_type NOT NULL
55
+ value TEXT NOT NULL
56
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
57
+ -- CONSTRAINT uq_fcl_type_value UNIQUE (type, value)
58
+ ```
59
+
60
+ ### `fonderie_customer_notes`
61
+
62
+ ```sql
63
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid()
64
+ customer_id UUID NOT NULL REFERENCES fonderie_customers(id) ON DELETE CASCADE
65
+ author_id UUID
66
+ body TEXT NOT NULL
67
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
68
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
69
+ ```
70
+
71
+ ### `fonderie_customer_phones`
72
+
73
+ ```sql
74
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid()
75
+ customer_id UUID NOT NULL REFERENCES fonderie_customers(id) ON DELETE CASCADE
76
+ phone TEXT NOT NULL
77
+ label TEXT NOT NULL DEFAULT 'mobile'
78
+ is_primary BOOLEAN NOT NULL DEFAULT false
79
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
80
+ label_id UUID REFERENCES fonderie_customer_labels(id)
81
+ CONSTRAINT fonderie_customer_phones_label_id_fkey FOREIGN KEY (label_id) REFERENCES fonderie_customer_labels(id) ON DELETE SET NULL
82
+ ```
83
+
84
+ ### `fonderie_customer_relationships`
85
+
86
+ ```sql
87
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid()
88
+ workspace_id UUID NOT NULL
89
+ customer_id UUID NOT NULL REFERENCES fonderie_customers(id) ON DELETE CASCADE
90
+ related_id UUID NOT NULL REFERENCES fonderie_customers(id) ON DELETE CASCADE
91
+ relationship TEXT NOT NULL
92
+ is_primary BOOLEAN NOT NULL DEFAULT false
93
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
94
+ -- UNIQUE (customer_id, related_id)
95
+ ```
96
+
97
+ ### `fonderie_customer_sequences`
98
+
99
+ ```sql
100
+ workspace_id UUID NOT NULL
101
+ prefix TEXT NOT NULL
102
+ next_val BIGINT NOT NULL DEFAULT 1
103
+ -- PRIMARY KEY (workspace_id, prefix)
104
+ ```
105
+
106
+ ### `fonderie_customer_tags`
107
+
108
+ ```sql
109
+ customer_id UUID NOT NULL REFERENCES fonderie_customers(id) ON DELETE CASCADE
110
+ tag TEXT NOT NULL
111
+ -- PRIMARY KEY (customer_id, tag)
112
+ ```
113
+
114
+ ### `fonderie_customers`
115
+
116
+ ```sql
117
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid()
118
+ workspace_id UUID NOT NULL
119
+ type TEXT NOT NULL DEFAULT 'individual'
120
+ first_name TEXT
121
+ last_name TEXT
122
+ company_name TEXT
123
+ avatar_url TEXT
124
+ locale TEXT NOT NULL DEFAULT 'en-US'
125
+ reference_code TEXT
126
+ is_blacklisted BOOLEAN NOT NULL DEFAULT false
127
+ created_by UUID
128
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
129
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
130
+ sex TEXT NOT NULL DEFAULT 'UNKNOWN'
131
+ blacklist_reason TEXT
132
+ ```
133
+
134
+ Raw SQL ships in `node_modules/@fonderie/customers/dist/migrations/sql/` — read it there if you must; never download tarballs.
135
+
136
+ ## Seeded rows (behavioral contract)
137
+
138
+ ```sql
139
+ INSERT INTO fonderie_customer_labels (type, value) VALUES ('email', 'work'), ('email', 'personal'), ('email', 'billing'), ('phone', 'mobile'), ('phone', 'office'), ('phone', 'home'), ('phone', 'fax'), ('address', 'service'), ('address', 'billing'), ('address', 'other') ON CONFLICT (type, value) DO NOTHING;
140
+ INSERT INTO fonderie_customer_labels (type, value) SELECT DISTINCT 'email'::fonderie_customer_label_type, label FROM fonderie_customer_emails WHERE label IS NOT NULL ON CONFLICT (type, value) DO NOTHING;
141
+ INSERT INTO fonderie_customer_labels (type, value) SELECT DISTINCT 'phone'::fonderie_customer_label_type, label FROM fonderie_customer_phones WHERE label IS NOT NULL ON CONFLICT (type, value) DO NOTHING;
142
+ INSERT INTO fonderie_customer_labels (type, value) SELECT DISTINCT 'address'::fonderie_customer_label_type, label FROM fonderie_customer_addresses WHERE label IS NOT NULL ON CONFLICT (type, value) DO NOTHING;
143
+ ```
144
+
145
+ ## HTTP routes registered
146
+
147
+ | Method | Path | Middleware chain (auth / validation / handler) |
148
+ |---|---|---|
149
+ | GET | `/customers` | `requireAuth → wsCtx → customer.list` |
150
+ | POST | `/customers` | `requireAuth → wsCtx → validate(createCustomerSchema) → customer.create` |
151
+ | DELETE | `/customers/:customerId` | `requireAuth → wsCtx → customer.delete` |
152
+ | GET | `/customers/:customerId` | `requireAuth → wsCtx → customer.get` |
153
+ | PUT | `/customers/:customerId` | `requireAuth → wsCtx → validate(updateCustomerSchema) → customer.update` |
154
+ | GET | `/customers/:customerId/addresses` | `requireAuth → wsCtx → address.list` |
155
+ | POST | `/customers/:customerId/addresses` | `requireAuth → wsCtx → validate(addAddressSchema) → address.add` |
156
+ | DELETE | `/customers/:customerId/addresses/:addrId` | `requireAuth → wsCtx → address.remove` |
157
+ | PATCH | `/customers/:customerId/addresses/:addrId` | `requireAuth → wsCtx → validate(updateAddressSchema) → address.update` |
158
+ | PUT | `/customers/:customerId/addresses/:addrId/primary` | `requireAuth → wsCtx → address.setPrimary` |
159
+ | POST | `/customers/:customerId/blacklist` | `requireAuth → wsCtx → validate(blacklistSchema) → customer.blacklist` |
160
+ | GET | `/customers/:customerId/emails` | `requireAuth → wsCtx → email.list` |
161
+ | POST | `/customers/:customerId/emails` | `requireAuth → wsCtx → validate(addEmailSchema) → email.add` |
162
+ | DELETE | `/customers/:customerId/emails/:emailId` | `requireAuth → wsCtx → email.remove` |
163
+ | PATCH | `/customers/:customerId/emails/:emailId` | `requireAuth → wsCtx → validate(updateEmailSchema) → email.update` |
164
+ | PUT | `/customers/:customerId/emails/:emailId/primary` | `requireAuth → wsCtx → email.setPrimary` |
165
+ | GET | `/customers/:customerId/notes` | `requireAuth → wsCtx → note.list` |
166
+ | POST | `/customers/:customerId/notes` | `requireAuth → wsCtx → validate(noteSchema) → note.create` |
167
+ | DELETE | `/customers/:customerId/notes/:noteId` | `requireAuth → wsCtx → note.delete` |
168
+ | PUT | `/customers/:customerId/notes/:noteId` | `requireAuth → wsCtx → validate(noteSchema) → note.update` |
169
+ | GET | `/customers/:customerId/phones` | `requireAuth → wsCtx → phone.list` |
170
+ | POST | `/customers/:customerId/phones` | `requireAuth → wsCtx → validate(addPhoneSchema) → phone.add` |
171
+ | DELETE | `/customers/:customerId/phones/:phoneId` | `requireAuth → wsCtx → phone.remove` |
172
+ | PATCH | `/customers/:customerId/phones/:phoneId` | `requireAuth → wsCtx → validate(updatePhoneSchema) → phone.update` |
173
+ | PUT | `/customers/:customerId/phones/:phoneId/primary` | `requireAuth → wsCtx → phone.setPrimary` |
174
+ | GET | `/customers/:customerId/relationships` | `requireAuth → wsCtx → relationship.list` |
175
+ | POST | `/customers/:customerId/relationships` | `requireAuth → wsCtx → validate(addRelationshipSchema) → relationship.add` |
176
+ | DELETE | `/customers/:customerId/relationships/:relatedId` | `requireAuth → wsCtx → relationship.remove` |
177
+ | PUT | `/customers/:customerId/relationships/:relatedId/primary` | `requireAuth → wsCtx → relationship.setPrimary` |
178
+ | GET | `/customers/:customerId/tags` | `requireAuth → wsCtx → tag.list` |
179
+ | POST | `/customers/:customerId/tags` | `requireAuth → wsCtx → validate(addTagSchema) → tag.add` |
180
+ | DELETE | `/customers/:customerId/tags/:tag` | `requireAuth → wsCtx → tag.remove` |
181
+ | POST | `/customers/:customerId/unblacklist` | `requireAuth → wsCtx → customer.unblacklist` |
182
+ | GET | `/customers/labels` | `requireAuth → wsCtx → label.list` |
183
+ | DELETE | `/customers/labels/:labelId` | `requireAuth → wsCtx → label.remove` |
184
+
185
+ ## Migration statements not replayed (verify in raw SQL)
186
+
187
+ - `END IF`
188
+ - `END $$`
189
+ - `CREATE TYPE fonderie_customer_label_type AS ENUM ('email', 'phone', 'address')`
@@ -0,0 +1,244 @@
1
+ <!-- GENERATED — do not edit. Regenerate with: npm run docs:signatures -->
2
+
3
+ # @fonderie/customers — signatures
4
+
5
+ ## @fonderie/customers
6
+
7
+ Subpath exports: `@fonderie/customers/types`, `@fonderie/customers/migrations`
8
+
9
+ ```ts
10
+ type CustomersEventKey = (typeof EVENT_KEYS)[keyof typeof EVENT_KEYS];
11
+
12
+ type ICustomersConfig = {
13
+ referenceCodePrefix?: string;
14
+ };
15
+
16
+ const EVENT_KEYS: { readonly customerCreated: "fonderie.customer.created"; readonly customerUpdated: "fonderie.customer.updated"; readonly customerDeleted: "fonderie.customer.deleted"; readonly customerBlacklisted: "fonderie.customer.blacklisted"; readonly customerUnblacklisted: "fonderie.customer.unblacklisted"; }
17
+
18
+ interface IAddressDTO {
19
+ countryIso: string;
20
+ subdivision1Iso: string;
21
+ subdivision2Iso: string;
22
+ zipPostalCode: string;
23
+ unit: string;
24
+ line1: string;
25
+ line2: string;
26
+ }
27
+
28
+ interface ICustomerAddressDTO {
29
+ id: string;
30
+ label: string;
31
+ isPrimary: boolean;
32
+ address: IAddressDTO;
33
+ }
34
+
35
+ interface ICustomerDetailDTO extends ICustomerDTO {
36
+ emails: ICustomerEmailDTO[];
37
+ phones: ICustomerPhoneDTO[];
38
+ addresses: ICustomerAddressDTO[];
39
+ notes: ICustomerNoteDTO[];
40
+ relationships: ICustomerRelationshipExpandedDTO[];
41
+ tags: string[];
42
+ }
43
+
44
+ interface ICustomerDTO {
45
+ id: string;
46
+ type: string;
47
+ sex: CustomerSex;
48
+ firstName: string;
49
+ lastName: string;
50
+ companyName: string;
51
+ avatarUrl: string;
52
+ locale: string;
53
+ referenceCode: string;
54
+ blacklisted: {
55
+ status: boolean;
56
+ reason: string | null;
57
+ };
58
+ createdBy: string;
59
+ createdAt: string;
60
+ updatedAt: string;
61
+ }
62
+
63
+ interface ICustomerEmailDTO {
64
+ id: string;
65
+ email: string;
66
+ label: string;
67
+ isPrimary: boolean;
68
+ createdAt: string;
69
+ }
70
+
71
+ interface ICustomerNoteDTO {
72
+ id: string;
73
+ authorId: string;
74
+ body: string;
75
+ createdAt: string;
76
+ updatedAt: string;
77
+ }
78
+
79
+ interface ICustomerPhoneDTO {
80
+ id: string;
81
+ phone: string;
82
+ label: string;
83
+ isPrimary: boolean;
84
+ createdAt: string;
85
+ }
86
+
87
+ interface ICustomerTagDTO {
88
+ tag: string;
89
+ }
90
+
91
+ function toAddressDTO(a: IAddress): IAddressDTO
92
+
93
+ function toCustomerAddressDTO(ca: ICustomerAddress): ICustomerAddressDTO
94
+
95
+ function toCustomerDetailDTO(c: ICustomerDetail): ICustomerDetailDTO
96
+
97
+ function toCustomerDTO(c: ICustomer): ICustomerDTO
98
+
99
+ function toCustomerEmailDTO(e: ICustomerEmail): ICustomerEmailDTO
100
+
101
+ function toCustomerNoteDTO(n: ICustomerNote): ICustomerNoteDTO
102
+
103
+ function toCustomerPhoneDTO(p: ICustomerPhone): ICustomerPhoneDTO
104
+
105
+ function toCustomerTagDTO(t: ICustomerTag): ICustomerTagDTO
106
+
107
+ new CustomerAddressModel(store: IStoreAdapter): CustomerAddressModel
108
+ .list(customerId: string): Promise<ICustomerAddress[]>
109
+ .add(opts: { customerId: string; countryIso: string; subdivision1Iso?: string | null; subdivision2Iso?: string | null; zipPostalCode: string; unit?: string | null; line1?: string | null; line2?: string | null; labelId: string; isPrimary?: boolean; }): Promise<...>
110
+ .updateLabel(addrId: string, customerId: string, labelId: string): Promise<ICustomerAddress>
111
+ .setPrimary(addrId: string, customerId: string): Promise<void>
112
+ .remove(addrId: string, customerId: string): Promise<void>
113
+
114
+ new CustomerEmailModel(store: IStoreAdapter): CustomerEmailModel
115
+ .list(customerId: string): Promise<ICustomerEmail[]>
116
+ .add(opts: { customerId: string; email: string; labelId: string; isPrimary?: boolean; }): Promise<ICustomerEmail>
117
+ .updateLabel(emailId: string, customerId: string, labelId: string): Promise<ICustomerEmail>
118
+ .setPrimary(emailId: string, customerId: string): Promise<void>
119
+ .remove(emailId: string, customerId: string): Promise<void>
120
+
121
+ new CustomerModel(store: IStoreAdapter): CustomerModel
122
+ .list(opts: ListCustomersOpts): Promise<ICustomer[]>
123
+ .findById(id: string, workspaceId: string): Promise<ICustomer | null>
124
+ .findDetail(id: string, workspaceId: string, depth: 2): Promise<ICustomerDetailD2 | null>
125
+ .create(opts: CreateCustomerOpts): Promise<ICustomer>
126
+ .update(id: string, workspaceId: string, opts: UpdateCustomerOpts, referenceCodePrefix?: string): Promise<ICustomer | null>
127
+ .delete(id: string, workspaceId: string): Promise<void>
128
+ .blacklist(id: string, workspaceId: string, reason?: string | null | undefined): Promise<void>
129
+ .unblacklist(id: string, workspaceId: string): Promise<void>
130
+
131
+ new CustomerNoteModel(store: IStoreAdapter): CustomerNoteModel
132
+ .list(customerId: string): Promise<ICustomerNote[]>
133
+ .create(opts: { customerId: string; authorId?: string | null; body: string; }): Promise<ICustomerNote>
134
+ .update(noteId: string, customerId: string, body: string): Promise<ICustomerNote | null>
135
+ .delete(noteId: string, customerId: string): Promise<void>
136
+
137
+ new CustomerPhoneModel(store: IStoreAdapter): CustomerPhoneModel
138
+ .list(customerId: string): Promise<ICustomerPhone[]>
139
+ .add(opts: { customerId: string; phone: string; labelId: string; isPrimary?: boolean; }): Promise<ICustomerPhone>
140
+ .updateLabel(phoneId: string, customerId: string, labelId: string): Promise<ICustomerPhone>
141
+ .setPrimary(phoneId: string, customerId: string): Promise<void>
142
+ .remove(phoneId: string, customerId: string): Promise<void>
143
+
144
+ new CustomerTagModel(store: IStoreAdapter): CustomerTagModel
145
+ .list(customerId: string): Promise<string[]>
146
+ .add(customerId: string, tag: string): Promise<void>
147
+ .remove(customerId: string, tag: string): Promise<void>
148
+
149
+ new CustomersModule(store: IStoreAdapter, config?: ICustomersConfig, bus?: EventBus | undefined): CustomersModule
150
+ .name: "@fonderie/customers"
151
+ .deps: string[]
152
+ .install(app: IFonderieApp): void
153
+
154
+ type AddressLabel = 'service' | 'billing' | 'other';
155
+
156
+ type CustomerType = 'individual' | 'business';
157
+
158
+ type EmailLabel = 'work' | 'personal' | 'billing';
159
+
160
+ interface IAddress {
161
+ id: string;
162
+ countryIso: string;
163
+ subdivision1Iso: string | null;
164
+ subdivision2Iso: string | null;
165
+ zipPostalCode: string;
166
+ unit: string | null;
167
+ line1: string | null;
168
+ line2: string | null;
169
+ }
170
+
171
+ interface ICustomer {
172
+ id: string;
173
+ workspaceId: string;
174
+ type: CustomerType;
175
+ sex: CustomerSex;
176
+ firstName: string | null;
177
+ lastName: string | null;
178
+ companyName: string | null;
179
+ avatarUrl: string | null;
180
+ locale: string;
181
+ referenceCode: string | null;
182
+ isBlacklisted: boolean;
183
+ blacklistReason: string | null;
184
+ createdBy: string | null;
185
+ createdAt: string;
186
+ updatedAt: string;
187
+ }
188
+
189
+ interface ICustomerAddress {
190
+ addrId: string;
191
+ customerId: string;
192
+ labelId: string;
193
+ label: string;
194
+ isPrimary: boolean;
195
+ address: IAddress;
196
+ }
197
+
198
+ interface ICustomerDetail extends ICustomer {
199
+ emails: ICustomerEmail[];
200
+ phones: ICustomerPhone[];
201
+ addresses: ICustomerAddress[];
202
+ notes: ICustomerNote[];
203
+ relationships: ICustomerRelationshipExpanded[];
204
+ tags: string[];
205
+ }
206
+
207
+ interface ICustomerEmail {
208
+ id: string;
209
+ customerId: string;
210
+ email: string;
211
+ labelId: string;
212
+ label: string;
213
+ isPrimary: boolean;
214
+ createdAt: string;
215
+ }
216
+
217
+ interface ICustomerNote {
218
+ id: string;
219
+ customerId: string;
220
+ authorId: string | null;
221
+ body: string;
222
+ createdAt: string;
223
+ updatedAt: string;
224
+ }
225
+
226
+ interface ICustomerPhone {
227
+ id: string;
228
+ customerId: string;
229
+ phone: string;
230
+ labelId: string;
231
+ label: string;
232
+ isPrimary: boolean;
233
+ createdAt: string;
234
+ }
235
+
236
+ interface ICustomerTag {
237
+ customerId: string;
238
+ tag: string;
239
+ }
240
+
241
+ type PhoneLabel = 'mobile' | 'office' | 'home' | 'fax';
242
+
243
+ namespace schemas — exports: addAddressSchema, addEmailSchema, addPhoneSchema, addRelationshipSchema, addTagSchema, blacklistSchema, createCustomerSchema, noteSchema, updateAddressSchema, updateCustomerSchema, updateEmailSchema, updatePhoneSchema
244
+ ```