gymmonk-schema 0.1.2 β 0.1.3
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/README.md +606 -57
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,93 +1,642 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ποΈ gymmonk-schema
|
|
2
|
+
|
|
3
|
+
> Central Zod v4 schema library for the GymMonk / Gym SaaS ecosystem.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/gymmonk-schema)
|
|
6
|
+
[](https://github.com/yourorg/gymmonk-schema/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## π Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Overview](#overview)
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
- [Core Concepts](#core-concepts)
|
|
15
|
+
- [Schemas vs Types](#schemas-vs-types)
|
|
16
|
+
- [Naming Conventions](#naming-conventions)
|
|
17
|
+
- [Library Structure](#library-structure)
|
|
18
|
+
- [Common](#common)
|
|
19
|
+
- [Auth](#auth)
|
|
20
|
+
- [Gym](#gym)
|
|
21
|
+
- [Workout](#workout)
|
|
22
|
+
- [Nutrition](#nutrition)
|
|
23
|
+
- [Subscription](#subscription)
|
|
24
|
+
- [Marketing](#marketing)
|
|
25
|
+
- [Notification](#notification)
|
|
26
|
+
- [Community](#community)
|
|
27
|
+
- [Feedback](#feedback)
|
|
28
|
+
- [Support](#support)
|
|
29
|
+
- [Landing](#landing)
|
|
30
|
+
- [Audit](#audit)
|
|
31
|
+
- [How to Import](#how-to-import)
|
|
32
|
+
- [Usage Examples](#usage-examples)
|
|
33
|
+
- [Backend (Express)](#backend-express)
|
|
34
|
+
- [Frontend (Next.js)](#frontend-nextjs)
|
|
35
|
+
- [Forms (React Hook Form + Zod)](#forms-react-hook-form--zod)
|
|
36
|
+
- [API-doc / OpenAPI](#api-doc--openapi)
|
|
37
|
+
- [Development & Publishing](#development--publishing)
|
|
38
|
+
- [Versioning](#versioning)
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## π― Overview
|
|
43
|
+
|
|
44
|
+
This package is the **single source of truth** for:
|
|
45
|
+
|
|
46
|
+
- β
Domain models (`User`, `Organisation`, `Center`, `Membership`, `Workout`, etc.)
|
|
47
|
+
- β
API DTOs (create/update payloads)
|
|
48
|
+
- β
Public view models (safe objects to send to frontend)
|
|
49
|
+
- β
Shared primitives (`ObjectId`, dates, pagination, etc.)
|
|
50
|
+
|
|
51
|
+
### π Designed for Multi-Platform Use
|
|
52
|
+
|
|
53
|
+
It is designed to be used by:
|
|
54
|
+
|
|
55
|
+
- **Backend** (Node.js / Express)
|
|
56
|
+
- **Web frontend** (Next.js)
|
|
57
|
+
- **Mobile app** (React Native)
|
|
58
|
+
- **API-doc project** (OpenAPI/Swagger via zod-to-openapi)
|
|
59
|
+
|
|
60
|
+
So all layers share the same contracts.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## π¦ Installation
|
|
65
|
+
|
|
66
|
+
In any consumer project (backend, web, app, api-doc):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install gymmonk-schema
|
|
70
|
+
# or
|
|
71
|
+
yarn add gymmonk-schema
|
|
72
|
+
# or
|
|
73
|
+
pnpm add gymmonk-schema
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## π‘ Core Concepts
|
|
79
|
+
|
|
80
|
+
### Schemas vs Types
|
|
81
|
+
|
|
82
|
+
Each entity is represented by a **Zod schema** and a corresponding **TypeScript type**:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { z } from "zod";
|
|
86
|
+
|
|
87
|
+
export const RoleSchema = z.object({
|
|
88
|
+
name: z.string().min(1),
|
|
89
|
+
description: z.string().trim().optional(),
|
|
90
|
+
permissions: z.array(z.string()).default([]),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export type Role = z.infer<typeof RoleSchema>;
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### Two Different Layers
|
|
97
|
+
|
|
98
|
+
| Layer | Description |
|
|
99
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
100
|
+
| **Schema** (`RoleSchema`) | β’ Real runtime object<br>β’ Validates and parses data<br>β’ Used in controllers, services, forms, API-doc generation |
|
|
101
|
+
| **Type** (`Role`) | β’ Compile-time only (erased at runtime)<br>β’ Used by TypeScript for static checking and autocomplete |
|
|
2
102
|
|
|
103
|
+
You will see this pattern throughout the library.
|
|
3
104
|
|
|
105
|
+
### Naming Conventions
|
|
4
106
|
|
|
5
|
-
|
|
107
|
+
Inside each domain:
|
|
6
108
|
|
|
7
|
-
|
|
109
|
+
- **Schemas** are named: `XxxSchema`
|
|
110
|
+
- **Types** are named: `Xxx` (via `z.infer<typeof XxxSchema>`)
|
|
111
|
+
- **DTOs** (request/response payloads) are named: `XxxCreateDtoSchema`, `XxxUpdateDtoSchema`, etc.
|
|
112
|
+
- **Public view models** (safe to send to frontend): `PublicXxxSchema`, `type PublicXxx`
|
|
8
113
|
|
|
9
|
-
|
|
114
|
+
---
|
|
10
115
|
|
|
11
|
-
##
|
|
116
|
+
## ποΈ Library Structure
|
|
12
117
|
|
|
13
|
-
|
|
14
|
-
- [ ] [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command:
|
|
118
|
+
At the top level, the package exposes namespaced domains:
|
|
15
119
|
|
|
120
|
+
```typescript
|
|
121
|
+
import {
|
|
122
|
+
Common,
|
|
123
|
+
Auth,
|
|
124
|
+
Gym,
|
|
125
|
+
Workout,
|
|
126
|
+
Nutrition,
|
|
127
|
+
Subscription,
|
|
128
|
+
Marketing,
|
|
129
|
+
Notification,
|
|
130
|
+
Community,
|
|
131
|
+
Feedback,
|
|
132
|
+
Support,
|
|
133
|
+
Landing,
|
|
134
|
+
Audit,
|
|
135
|
+
} from "gymmonk-schema";
|
|
16
136
|
```
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
137
|
+
|
|
138
|
+
Each domain has its own folder + barrel file and follows the same structure: schemas + types grouped by feature.
|
|
139
|
+
|
|
140
|
+
Below is an overview of what each domain represents.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### π§ Common
|
|
145
|
+
|
|
146
|
+
Building blocks used everywhere.
|
|
147
|
+
|
|
148
|
+
#### Includes:
|
|
149
|
+
|
|
150
|
+
**Primitives**
|
|
151
|
+
|
|
152
|
+
- `ObjectIdSchema`
|
|
153
|
+
- `IsoDateStringSchema`
|
|
154
|
+
- `IsoDateTimeStringSchema`
|
|
155
|
+
- `NonEmptyStringSchema`, `OptionalStringSchema`, etc.
|
|
156
|
+
|
|
157
|
+
**Value Objects**
|
|
158
|
+
|
|
159
|
+
- `EmailSchema`
|
|
160
|
+
- `PhoneSchema`
|
|
161
|
+
- `AddressSchema`
|
|
162
|
+
- `NutritionalValuesSchema`
|
|
163
|
+
- `PlanVariantSchema` (for flexible pricing options)
|
|
164
|
+
- `MfaSchema`, `SocialLoginSchema`, etc.
|
|
165
|
+
|
|
166
|
+
**Enums**
|
|
167
|
+
|
|
168
|
+
- Gender enum
|
|
169
|
+
- EntityStatus enum
|
|
170
|
+
- NotificationType enum
|
|
171
|
+
|
|
172
|
+
**Pagination**
|
|
173
|
+
|
|
174
|
+
- `PaginationSchema` (common page, limit, etc.)
|
|
175
|
+
|
|
176
|
+
#### Usage Example
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
const id = Common.Primitives.ObjectIdSchema.parse(someString);
|
|
180
|
+
const pagination = Common.Pagination.PaginationSchema.parse(req.query);
|
|
21
181
|
```
|
|
22
182
|
|
|
23
|
-
|
|
183
|
+
> βΉοΈ _Exact nested names may vary slightly; check `src/common/index.ts` for the authoritative exports._
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### π Auth
|
|
188
|
+
|
|
189
|
+
Authentication & authorization related models.
|
|
190
|
+
|
|
191
|
+
#### Includes (names representative):
|
|
192
|
+
|
|
193
|
+
- `UserSchema`, `PublicUserSchema`, `UserRegisterDtoSchema` etc.
|
|
194
|
+
- `RoleSchema` (RBAC roles)
|
|
195
|
+
- `PermissionSchema` (fine-grained permissions)
|
|
196
|
+
- `ResourceSchema` (RBAC resources)
|
|
197
|
+
- `TokenSchema` (access/refresh tokens, device tokens)
|
|
198
|
+
- `OtpSchema` (one-time passwords)
|
|
199
|
+
- `DeviceSchema`
|
|
200
|
+
- `PasswordHistorySchema`
|
|
201
|
+
- `UserActivitySchema` (login, logout, etc.)
|
|
202
|
+
|
|
203
|
+
#### Common Usage:
|
|
204
|
+
|
|
205
|
+
- **Backend**: validate incoming auth requests (register, login, password reset)
|
|
206
|
+
- **Frontend**: type-safe forms for login/register, and PublicUser types for UI
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### π’ Gym
|
|
211
|
+
|
|
212
|
+
All gym/organisation/center management models.
|
|
213
|
+
|
|
214
|
+
#### Includes:
|
|
215
|
+
|
|
216
|
+
**Organisation / Centers**
|
|
217
|
+
|
|
218
|
+
- `OrganisationSchema`
|
|
219
|
+
- `CenterSchema`
|
|
220
|
+
- `CenterFacilitySchema`
|
|
221
|
+
- `CenterServiceSchema`
|
|
222
|
+
|
|
223
|
+
**Catalogs**
|
|
224
|
+
|
|
225
|
+
- `EquipmentCatalogSchema`
|
|
226
|
+
- `FacilityCatalogSchema`
|
|
227
|
+
- `ServiceCatalogSchema`
|
|
228
|
+
|
|
229
|
+
**Operational Models**
|
|
230
|
+
|
|
231
|
+
- `AttendanceSchema`
|
|
232
|
+
- `ClassScheduleSchema`
|
|
233
|
+
- `EquipmentInventorySchema`
|
|
234
|
+
- `GymLayoutSchema`
|
|
235
|
+
- `SessionBookingSchema`
|
|
236
|
+
- `GoalSchema`
|
|
237
|
+
- `AchievementBadgeSchema`
|
|
238
|
+
|
|
239
|
+
#### Used to Define and Validate:
|
|
240
|
+
|
|
241
|
+
- How the gym, centers, facilities, services are modeled
|
|
242
|
+
- Attendance tracking
|
|
243
|
+
- Booking / layout / goals / badges
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### πͺ Workout
|
|
248
|
+
|
|
249
|
+
Exercise and workout planning & tracking.
|
|
250
|
+
|
|
251
|
+
#### Includes:
|
|
252
|
+
|
|
253
|
+
- `ExerciseSchema` (name, muscle groups, media, equipment)
|
|
254
|
+
- `WorkoutPlanSchema` (list of exercises with sets/reps/duration)
|
|
255
|
+
- `WorkoutTrackingEntrySchema` (what a member actually did, per set, per day)
|
|
256
|
+
|
|
257
|
+
#### Used By:
|
|
258
|
+
|
|
259
|
+
- **Backend**: workout CRUD, tracking endpoints
|
|
260
|
+
- **Frontend/App**: typed workout UI, tracking screens
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### π₯ Nutrition
|
|
265
|
+
|
|
266
|
+
Ingredient, recipes, diet plans, hydration.
|
|
267
|
+
|
|
268
|
+
#### Includes:
|
|
269
|
+
|
|
270
|
+
- `IngredientSchema`
|
|
271
|
+
- `RecipeSchema`, `RecipeIngredientSchema`
|
|
272
|
+
- `DietPlanSchema`, `DietPlanMealSchema`, `DietPlanItemSchema`
|
|
273
|
+
- `DietTrackingEntrySchema`
|
|
274
|
+
- `HydrationTrackingSchema`
|
|
275
|
+
|
|
276
|
+
#### Use This For:
|
|
277
|
+
|
|
278
|
+
- Building diet plans and logging diets
|
|
279
|
+
- Aggregating nutrition
|
|
280
|
+
- Hydration tracking
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
### π³ Subscription
|
|
285
|
+
|
|
286
|
+
Subscription, membership, coupons, payments.
|
|
287
|
+
|
|
288
|
+
#### Includes:
|
|
289
|
+
|
|
290
|
+
- `SubscriptionPlanSchema`
|
|
291
|
+
- `SubscriptionSchema`
|
|
292
|
+
- `MembershipPlanSchema`
|
|
293
|
+
- `MembershipSchema`
|
|
294
|
+
- `CouponSchema`
|
|
295
|
+
- `PaymentTransactionSchema`
|
|
296
|
+
|
|
297
|
+
#### Used For:
|
|
298
|
+
|
|
299
|
+
- Defining product plans and membership plans
|
|
300
|
+
- Linking members to plans (Membership, Subscription)
|
|
301
|
+
- Applying coupons and tracking payments
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
### π’ Marketing
|
|
306
|
+
|
|
307
|
+
Branding, ads, campaigns, referrals.
|
|
308
|
+
|
|
309
|
+
#### Includes:
|
|
310
|
+
|
|
311
|
+
- `BrandSchema`
|
|
312
|
+
- `AdvertisementSchema`
|
|
313
|
+
- `MarketingCampaignSchema`
|
|
314
|
+
- `ReferralSchema`
|
|
315
|
+
|
|
316
|
+
#### Used For:
|
|
317
|
+
|
|
318
|
+
- Dashboard banners, campaigns, referral systems
|
|
319
|
+
- Representing marketing data in a unified way
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
### π Notification
|
|
324
|
+
|
|
325
|
+
Notifications and templates.
|
|
326
|
+
|
|
327
|
+
#### Includes:
|
|
328
|
+
|
|
329
|
+
- `NotificationSchema` (delivered notification entries)
|
|
330
|
+
- `NotificationTemplateSchema` (reusable templates per channel)
|
|
331
|
+
|
|
332
|
+
**Supports channels like**: `in_app`, `push`, `email`, `sms`.
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
### π₯ Community
|
|
337
|
+
|
|
338
|
+
Internal community / communication layer.
|
|
339
|
+
|
|
340
|
+
#### Includes:
|
|
341
|
+
|
|
342
|
+
- `ConversationSchema`
|
|
343
|
+
- `MessageSchema`
|
|
344
|
+
- `PostSchema`
|
|
345
|
+
|
|
346
|
+
#### Used For:
|
|
347
|
+
|
|
348
|
+
- Chats
|
|
349
|
+
- Group conversations
|
|
350
|
+
- Community posts
|
|
24
351
|
|
|
25
|
-
|
|
352
|
+
---
|
|
26
353
|
|
|
27
|
-
|
|
354
|
+
### π¬ Feedback
|
|
28
355
|
|
|
29
|
-
|
|
30
|
-
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
|
|
31
|
-
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
|
32
|
-
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
|
|
33
|
-
- [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/)
|
|
356
|
+
User feedback, bug reports, ratings.
|
|
34
357
|
|
|
35
|
-
|
|
358
|
+
#### Includes:
|
|
36
359
|
|
|
37
|
-
|
|
360
|
+
- `FeedbackSchema` (type, message, metadata, rating)
|
|
38
361
|
|
|
39
|
-
|
|
40
|
-
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
|
|
41
|
-
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
|
|
42
|
-
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
|
|
43
|
-
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
|
362
|
+
---
|
|
44
363
|
|
|
45
|
-
|
|
364
|
+
### π« Support
|
|
46
365
|
|
|
47
|
-
|
|
366
|
+
Support tickets.
|
|
48
367
|
|
|
49
|
-
|
|
368
|
+
#### Includes:
|
|
50
369
|
|
|
51
|
-
|
|
370
|
+
- `SupportTicketSchema` (priority, status, category, assignments, metadata)
|
|
52
371
|
|
|
53
|
-
|
|
372
|
+
---
|
|
54
373
|
|
|
55
|
-
|
|
56
|
-
Choose a self-explaining name for your project.
|
|
374
|
+
### π Landing
|
|
57
375
|
|
|
58
|
-
|
|
59
|
-
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
|
|
376
|
+
Contact requests from marketing/landing pages.
|
|
60
377
|
|
|
61
|
-
|
|
62
|
-
|
|
378
|
+
#### Includes:
|
|
379
|
+
|
|
380
|
+
- `ContactRequestSchema` (name, email/phone, subject, message, metadata)
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### π Audit
|
|
385
|
+
|
|
386
|
+
Audit logs.
|
|
387
|
+
|
|
388
|
+
#### Includes:
|
|
389
|
+
|
|
390
|
+
- `AuditLogSchema` (who, what, when, before/after, metadata)
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## π₯ How to Import
|
|
395
|
+
|
|
396
|
+
### Top-Level Domains (Recommended)
|
|
397
|
+
|
|
398
|
+
Prefer importing from the root in most cases:
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
import {
|
|
402
|
+
Auth,
|
|
403
|
+
Gym,
|
|
404
|
+
Subscription,
|
|
405
|
+
Workout,
|
|
406
|
+
Nutrition,
|
|
407
|
+
Common,
|
|
408
|
+
} from "gymmonk-schema";
|
|
409
|
+
|
|
410
|
+
// Auth
|
|
411
|
+
const dto = Auth.UserRegisterDtoSchema.parse(body);
|
|
412
|
+
|
|
413
|
+
// Gym
|
|
414
|
+
const center = Gym.CenterSchema.parse(payload);
|
|
415
|
+
|
|
416
|
+
// Subscription
|
|
417
|
+
type Plan = Subscription.SubscriptionPlan;
|
|
418
|
+
const planSchema = Subscription.SubscriptionPlanSchema;
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
> π‘ If you want very fine-grained imports, you can also import directly from subpaths as long as your build/exports are configured for it (check your `package.json` "exports" if you add that later).
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## π¨ Usage Examples
|
|
426
|
+
|
|
427
|
+
### Backend (Express)
|
|
428
|
+
|
|
429
|
+
#### Validate Request Body (DTO)
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
import { Auth } from "gymmonk-schema";
|
|
433
|
+
import type { Request, Response } from "express";
|
|
434
|
+
|
|
435
|
+
export async function registerHandler(req: Request, res: Response) {
|
|
436
|
+
try {
|
|
437
|
+
const dto = Auth.UserRegisterDtoSchema.parse(req.body);
|
|
438
|
+
|
|
439
|
+
// dto is fully validated and typed
|
|
440
|
+
const user = await createUser(dto);
|
|
441
|
+
|
|
442
|
+
const publicUser = Auth.PublicUserSchema.parse(user);
|
|
443
|
+
return res.status(201).json(publicUser);
|
|
444
|
+
} catch (err: any) {
|
|
445
|
+
return res.status(400).json({
|
|
446
|
+
message: "Invalid request",
|
|
447
|
+
errors: err.errors ?? err,
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
#### Validate Query Params
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
import { Common } from "gymmonk-schema";
|
|
457
|
+
|
|
458
|
+
app.get("/centers", (req, res) => {
|
|
459
|
+
const pagination = Common.Pagination.PaginationSchema.parse(req.query);
|
|
460
|
+
// use pagination.page / pagination.limit
|
|
461
|
+
});
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
### Frontend (Next.js)
|
|
467
|
+
|
|
468
|
+
#### Validate Data Before Sending to Backend
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
"use client";
|
|
472
|
+
|
|
473
|
+
import { Auth } from "gymmonk-schema";
|
|
474
|
+
|
|
475
|
+
async function submit(formData: any) {
|
|
476
|
+
const dto = Auth.UserRegisterDtoSchema.parse(formData);
|
|
477
|
+
|
|
478
|
+
const res = await fetch("/api/auth/register", {
|
|
479
|
+
method: "POST",
|
|
480
|
+
body: JSON.stringify(dto),
|
|
481
|
+
headers: { "Content-Type": "application/json" },
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
return res.json();
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
#### Strongly Typed UI Components
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
import { Gym } from "gymmonk-schema";
|
|
492
|
+
|
|
493
|
+
type Center = Gym.Center;
|
|
494
|
+
|
|
495
|
+
function CenterCard({ center }: { center: Center }) {
|
|
496
|
+
return (
|
|
497
|
+
<div>
|
|
498
|
+
<h2>{center.name}</h2>
|
|
499
|
+
<p>{center.address?.city}</p>
|
|
500
|
+
</div>
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
### Forms (React Hook Form + Zod)
|
|
508
|
+
|
|
509
|
+
```typescript
|
|
510
|
+
import { useForm } from "react-hook-form";
|
|
511
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
512
|
+
import { Subscription } from "gymmonk-schema";
|
|
513
|
+
|
|
514
|
+
const schema = Subscription.SubscriptionPlanSchema;
|
|
515
|
+
type PlanForm = Subscription.SubscriptionPlan;
|
|
516
|
+
|
|
517
|
+
export function PlanFormComponent() {
|
|
518
|
+
const form = useForm<PlanForm>({
|
|
519
|
+
resolver: zodResolver(schema),
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
// form.register, form.handleSubmit, etc.
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
### API-doc / OpenAPI
|
|
529
|
+
|
|
530
|
+
In your API-doc project (contract-first design), you can introspect schemas and generate OpenAPI:
|
|
531
|
+
|
|
532
|
+
```typescript
|
|
533
|
+
import {
|
|
534
|
+
OpenAPIRegistry,
|
|
535
|
+
generateOpenApiDocument,
|
|
536
|
+
} from "@asteasolutions/zod-to-openapi";
|
|
537
|
+
import { Auth, Gym } from "gymmonk-schema";
|
|
538
|
+
|
|
539
|
+
const registry = new OpenAPIRegistry();
|
|
540
|
+
|
|
541
|
+
// Register schemas
|
|
542
|
+
registry.register("User", Auth.PublicUserSchema);
|
|
543
|
+
registry.register("Center", Gym.CenterSchema);
|
|
544
|
+
|
|
545
|
+
// Register routes and use the schemas in request/response definitionsβ¦
|
|
546
|
+
|
|
547
|
+
const openapi = generateOpenApiDocument(registry.definitions, {
|
|
548
|
+
openapi: "3.0.0",
|
|
549
|
+
info: {
|
|
550
|
+
title: "GymMonk API",
|
|
551
|
+
version: "1.0.0",
|
|
552
|
+
},
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
// Then write openapi.json and serve via swagger-ui-express
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
This way API docs are always in sync with your code and frontend types.
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
## π οΈ Development & Publishing
|
|
563
|
+
|
|
564
|
+
In the `gymmonk-schema` repo:
|
|
565
|
+
|
|
566
|
+
### Build
|
|
567
|
+
|
|
568
|
+
```bash
|
|
569
|
+
npm run build
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Typical script:**
|
|
573
|
+
|
|
574
|
+
```json
|
|
575
|
+
"build": "tsc"
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
This compiles `src/**/*.ts` β `dist/**/*.js` + `.d.ts`.
|
|
579
|
+
|
|
580
|
+
### Lint + Format
|
|
581
|
+
|
|
582
|
+
Using Biome:
|
|
583
|
+
|
|
584
|
+
```bash
|
|
585
|
+
npm run check # type-check + lint + format (depending on your script)
|
|
586
|
+
npm run lint # if you have a separate lint script
|
|
587
|
+
npm run format # if you have a separate format script
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Version Bump
|
|
591
|
+
|
|
592
|
+
Use semantic versioning:
|
|
593
|
+
|
|
594
|
+
```bash
|
|
595
|
+
npm version patch # 0.1.0 -> 0.1.1
|
|
596
|
+
npm version minor # 0.1.0 -> 0.2.0
|
|
597
|
+
npm version major # 0.1.0 -> 1.0.0
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
This updates `package.json` and creates a git commit + tag (if configured).
|
|
601
|
+
|
|
602
|
+
### Publish
|
|
603
|
+
|
|
604
|
+
```bash
|
|
605
|
+
npm login
|
|
606
|
+
npm run build
|
|
607
|
+
npm publish --access public
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
Then consumers can install:
|
|
611
|
+
|
|
612
|
+
```bash
|
|
613
|
+
npm install gymmonk-schema
|
|
614
|
+
```
|
|
63
615
|
|
|
64
|
-
|
|
65
|
-
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
|
|
616
|
+
---
|
|
66
617
|
|
|
67
|
-
##
|
|
68
|
-
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
|
|
618
|
+
## π Versioning
|
|
69
619
|
|
|
70
|
-
|
|
71
|
-
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
|
|
620
|
+
Follow standard **SemVer**:
|
|
72
621
|
|
|
73
|
-
|
|
74
|
-
|
|
622
|
+
| Version Type | Pattern | Description |
|
|
623
|
+
| ------------ | ------- | ---------------------------------------------------------------- |
|
|
624
|
+
| **PATCH** | `x.y.Z` | Internal fixes, no breaking changes |
|
|
625
|
+
| **MINOR** | `x.Y.z` | New schemas/fields added in a backwards-compatible way |
|
|
626
|
+
| **MAJOR** | `X.y.z` | Breaking changes (removed fields, renamed, incompatible changes) |
|
|
75
627
|
|
|
76
|
-
|
|
77
|
-
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
|
628
|
+
### Guidelines:
|
|
78
629
|
|
|
79
|
-
|
|
80
|
-
|
|
630
|
+
- β
**Adding optional fields**: minor
|
|
631
|
+
- β οΈ **Making a field required or changing its type**: major
|
|
632
|
+
- β οΈ **Removing schemas or renaming them**: major
|
|
81
633
|
|
|
82
|
-
|
|
634
|
+
> π Keep a simple `CHANGELOG.md` to track what changed between versions, especially when schemas or DTOs change in ways that affect consumers.
|
|
83
635
|
|
|
84
|
-
|
|
636
|
+
---
|
|
85
637
|
|
|
86
|
-
|
|
87
|
-
Show your appreciation to those who have contributed to the project.
|
|
638
|
+
<div align="center">
|
|
88
639
|
|
|
89
|
-
|
|
90
|
-
For open source projects, say how it is licensed.
|
|
640
|
+
**Built with β€οΈ for the GymMonk ecosystem**
|
|
91
641
|
|
|
92
|
-
|
|
93
|
-
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
|
642
|
+
</div>
|