@goweekdays/core 2.13.0 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @goweekdays/core
2
2
 
3
+ ## 2.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 770a91a: Finance business profile initial release
8
+
9
+ ### Patch Changes
10
+
11
+ - c54c430: Integrate account balance tracker
12
+ - b31181e: Support updating journal entries with line diffing
13
+
14
+ ## 2.14.0
15
+
16
+ ### Minor Changes
17
+
18
+ - a604a6f: Initial release for finance journal and ledger
19
+
20
+ ### Patch Changes
21
+
22
+ - 29b0676: Add indexes, search and fields for journal lines
23
+
3
24
  ## 2.13.0
4
25
 
5
26
  ### Minor Changes
package/CLAUDE.md ADDED
@@ -0,0 +1,274 @@
1
+ # server-core-module (`@goweekdays/core`)
2
+
3
+ Shared server module exported as a package consumed by all app servers.
4
+ Built with Express + MongoDB (Atlas) + TypeScript.
5
+
6
+ ## Resource Layer Pattern
7
+
8
+ Each resource lives under `src/resources/<resource-name>/` and follows this structure:
9
+
10
+ ```
11
+ resource-name/
12
+ resource.model.ts # Types and validation schema
13
+ resource.repository.ts # Direct database interaction
14
+ resource.service.ts # Business logic (optional — see below)
15
+ resource.controller.ts # API request handler
16
+ index.ts # Barrel export
17
+ ```
18
+
19
+ ### `.model.ts`
20
+
21
+ Defines the TypeScript type and Joi validation schema for the resource. This is the source of truth for the shape of the data.
22
+
23
+ ### `.repository.ts`
24
+
25
+ Contains all functions that directly interact with the database (MongoDB). No business logic here — only reads and writes.
26
+
27
+ ### `.service.ts`
28
+
29
+ Builds business logic by composing repository functions and third-party integrations (e.g. hashing, email, S3, transactions). Never accesses the database directly — all DB interaction goes through the repository. **This layer is optional** — if a resource only needs basic CRUD with no business logic, a service file is not required.
30
+
31
+ ### `.controller.ts`
32
+
33
+ Handles incoming API requests. Validates the request input, then delegates to the service layer if business logic exists, or calls the repository directly if the resource has no service.
34
+
35
+ ### `index.ts`
36
+
37
+ Re-exports all layers so consumers can import from the resource folder directly.
38
+
39
+ ```typescript
40
+ export * from "./user.model";
41
+ export * from "./user.repository";
42
+ export * from "./user.service";
43
+ export * from "./user.controller";
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Naming Conventions
49
+
50
+ | Layer | Pattern | Example |
51
+ | ---------- | --------------------------- | ---------------------------------------------------- |
52
+ | File | `<resource>.<layer>.ts` | `user.model.ts`, `finance.journal.config.service.ts` |
53
+ | Type | `T<Resource>` | `TUser`, `TJobPost` |
54
+ | Schema | `schema<Resource>` | `schemaUser`, `schemaJobPost` |
55
+ | Model fn | `model<Resource>()` | `modelUser()`, `modelJobPost()` |
56
+ | Repository | `use<Resource>Repo()` | `useUserRepo()`, `useOrgRepo()` |
57
+ | Service | `use<Resource>Service()` | `useUserService()`, `useOrgService()` |
58
+ | Controller | `use<Resource>Controller()` | `useUserController()` |
59
+
60
+ Multi-word resource names use dot notation in file names: `finance.journal.config.model.ts`, `job.post.repository.ts`.
61
+
62
+ ---
63
+
64
+ ## Error Handling
65
+
66
+ Always use the typed error classes from `@goweekdays/utils` — never throw a generic `new Error()`.
67
+
68
+ - `BadRequestError` — invalid input or a violated business rule
69
+ - `NotFoundError` — resource does not exist
70
+ - `InternalServerError` — unexpected DB or system failure
71
+ - `AppError` — base class; use `instanceof AppError` in catch blocks to re-throw typed errors as-is
72
+
73
+ ---
74
+
75
+ ## Controller Input Extraction
76
+
77
+ Validate the entire `req.body` against a Joi schema to ensure no unexpected keys are passed. Extract only the fields you need after validation.
78
+
79
+ 1. Define a Joi schema that describes exactly the expected shape
80
+ 2. Validate `req.body` (or `req.params` / `req.query`) against it — reject if invalid
81
+ 3. Destructure only the needed fields from the validated result
82
+ 4. Delegate to the service or repository
83
+
84
+ This prevents unexpected or extra fields from leaking into the database.
85
+
86
+ ---
87
+
88
+ ## Transactions
89
+
90
+ Use a MongoDB session whenever a service function writes to more than one collection. The pattern is always:
91
+
92
+ 1. Start session and transaction
93
+ 2. Pass `session` down to every repo call
94
+ 3. Commit on success, abort on error, and always end the session in `finally`
95
+
96
+ Transactions belong in the service layer only — never in a controller or repository.
97
+
98
+ ---
99
+
100
+ ## What Not To Do
101
+
102
+ - **No business logic in controllers** — controllers only handle HTTP input/output and delegate
103
+ - **No direct DB access in controllers or services** — all DB interaction belongs in the repository only
104
+ - **No generic `Error` throws** — use the typed error classes above
105
+ - **No Zod** — validation is done with Joi throughout this module
106
+ - **No extra fields into the DB** — always validate the full request body before using any of it
107
+
108
+ # Monthly Account Balance Tracking — Instruction Set
109
+
110
+ ## Objective
111
+
112
+ Maintain a monthly balance tracker for each account using the structure:
113
+
114
+ (accountId, fiscalYear, month)
115
+
116
+ Each record must contain:
117
+
118
+ - openingDebit
119
+ - openingCredit
120
+ - movementDebit
121
+ - movementCredit
122
+ - closingDebit
123
+ - closingCredit
124
+ - netBalance
125
+
126
+ ---
127
+
128
+ # 1. When Posting a Journal Entry
129
+
130
+ For each journal line in a transaction:
131
+
132
+ 1. Identify:
133
+
134
+ - accountId
135
+ - transactionDate
136
+ - month
137
+ - fiscalYear
138
+ - debitAmount
139
+ - creditAmount
140
+
141
+ 2. Locate the balance record:
142
+
143
+ (accountId, fiscalYear, month)
144
+
145
+ ---
146
+
147
+ # 2. If Balance Record Exists
148
+
149
+ Update the movement values.
150
+
151
+ If the journal line is debit:
152
+
153
+ movementDebit += debitAmount
154
+
155
+ If the journal line is credit:
156
+
157
+ movementCredit += creditAmount
158
+
159
+ Then recompute the closing balance.
160
+
161
+ ---
162
+
163
+ # 3. If Balance Record Does NOT Exist
164
+
165
+ Create a new balance record.
166
+
167
+ Determine the opening balance using the following rules.
168
+
169
+ ## Rule A — Previous Month Record Exists
170
+
171
+ Find the latest previous balance record for the same account.
172
+
173
+ (accountId, previousMonth, fiscalYear)
174
+
175
+ Set the opening balance:
176
+
177
+ openingDebit = previousRecord.closingDebit
178
+ openingCredit = previousRecord.closingCredit
179
+
180
+ ## Rule B — No Previous Record Exists
181
+
182
+ This means the account is used for the first time.
183
+
184
+ Set:
185
+
186
+ openingDebit = 0
187
+ openingCredit = 0
188
+
189
+ ## Initialize Movement
190
+
191
+ After determining the opening balance:
192
+
193
+ movementDebit = debitAmount
194
+ movementCredit = creditAmount
195
+
196
+ ---
197
+
198
+ # 4. Recompute Closing Balance
199
+
200
+ After movement updates, compute the net balance.
201
+
202
+ netBalance = (openingDebit + movementDebit) - (openingCredit + movementCredit)
203
+
204
+ If netBalance > 0:
205
+
206
+ closingDebit = netBalance
207
+ closingCredit = 0
208
+
209
+ If netBalance < 0:
210
+
211
+ closingDebit = 0
212
+ closingCredit = abs(netBalance)
213
+
214
+ If netBalance == 0:
215
+
216
+ closingDebit = 0
217
+ closingCredit = 0
218
+
219
+ The `netBalance` field should always store the computed value so the system can quickly determine whether the account has a debit or credit balance without recalculating.
220
+
221
+ ---
222
+
223
+ # 5. Month-to-Month Carry Forward Rule
224
+
225
+ When a new month record is created:
226
+
227
+ opening balance = previous month closing balance
228
+
229
+ Example:
230
+
231
+ January closing = 8,000 debit
232
+ February opening = 8,000 debit
233
+
234
+ ---
235
+
236
+ # 6. Summary of Posting Flow
237
+
238
+ For each journal line:
239
+
240
+ 1. Determine account, fiscalYear, and month
241
+ 2. Find balance record
242
+ 3. If record exists → update movement
243
+ 4. If record does not exist
244
+
245
+ - find previous balance record
246
+ - set opening = previous closing (or zero)
247
+ - create new balance record
248
+
249
+ 5. Update movement values
250
+ 6. Recompute closing balance
251
+
252
+ ---
253
+
254
+ # 7. Important Principle
255
+
256
+ Opening balance always represents:
257
+
258
+ balance before the period starts
259
+
260
+ Therefore:
261
+
262
+ opening = previous closing
263
+
264
+ If no previous record exists:
265
+
266
+ opening = 0
267
+
268
+ ---
269
+
270
+ This logic ensures:
271
+
272
+ - continuous balance tracking
273
+ - correct month-to-month carry over
274
+ - efficient financial reporting without recalculating all journal entries