Skip to content

Commit f57b223

Browse files
committed
fixed schedule table, timeslots, youtube_url and update times
1 parent ba9a262 commit f57b223

5 files changed

Lines changed: 39 additions & 51 deletions

File tree

docs/coaching.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ erDiagram
1414
session_status status "pending | confirmed | cancelled | completed"
1515
text meeting_url
1616
text notes
17-
time[] selected_time_slots
17+
jsonb selected_time_slots "array of {start, end} objects"
1818
timestamp created_at
19+
timestamp updated_at
1920
}
2021
2122
profiles ||--o{ coaching_sessions : "coach leads"
@@ -26,6 +27,6 @@ erDiagram
2627
## Notes
2728

2829
- `scheduled_at` is null by default — it is set once the user selects a specific slot from `selected_time_slots`.
29-
- `selected_time_slots` holds the time options offered to the user before a slot is confirmed.
30+
- `selected_time_slots` is a JSON array of `{ start, end }` objects (ISO 8601 strings) representing the time options offered to the user e.g. `[{ "start": "2026-04-14T14:00:00Z", "end": "2026-04-14T17:00:00Z" }]`.
3031
- `meeting_url` is provided by the coach after confirmation.
3132
- `status = completed` is set after the session ends.

docs/schema-overview.md

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ erDiagram
2121
int price
2222
boolean is_active
2323
timestamp created_at
24+
timestamp updated_at
2425
}
2526
26-
schedules {
27+
service_schedules {
2728
uuid id PK
2829
uuid service_id FK
2930
jsonb data
3031
timestamp created_at
32+
timestamp updated_at
3133
}
3234
3335
service_bookings {
@@ -38,6 +40,7 @@ erDiagram
3840
text notes
3941
boolean is_active
4042
timestamp created_at
43+
timestamp updated_at
4144
}
4245
4346
webinars {
@@ -46,16 +49,10 @@ erDiagram
4649
text description
4750
webinar_tier tier
4851
int duration_minutes
49-
text meeting_url
52+
text youtube_url
5053
boolean is_active
5154
timestamp created_at
52-
}
53-
54-
webinar_registrations {
55-
uuid id PK
56-
uuid user_id FK
57-
uuid webinar_id FK
58-
timestamp registered_at
55+
timestamp updated_at
5956
}
6057
6158
coaching_sessions {
@@ -68,15 +65,14 @@ erDiagram
6865
session_status status
6966
text meeting_url
7067
text notes
71-
time[] selected_time_slots
68+
jsonb selected_time_slots "array of {start, end} objects"
7269
timestamp created_at
70+
timestamp updated_at
7371
}
7472
75-
services ||--o| schedules : "has schedule"
73+
services ||--o| service_schedules : "has schedule"
7674
profiles ||--o{ service_bookings : "books"
7775
services ||--o{ service_bookings : "booked via"
78-
profiles ||--o{ webinar_registrations : "registers"
79-
webinars ||--o{ webinar_registrations : "has"
8076
profiles ||--o{ coaching_sessions : "coaches"
8177
profiles ||--o{ coaching_sessions : "attends"
8278
services ||--o{ coaching_sessions : "fulfilled by"

docs/services.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
## Services
44

55
The central catalog of offerings on the platform. Two types:
6-
- **`booking`** — a bookable service; has an associated `schedules` row (via `scheduling_id`).
6+
- **`booking`** — a bookable service; has an associated `service_schedules` row (via `scheduling_id`).
77
- **`coaching_session`** — a coaching offering; `scheduling_id` is null — the scheduling is handled through the `coaching_sessions` table.
88

99
```mermaid
@@ -21,17 +21,18 @@ erDiagram
2121
}
2222
```
2323

24-
## Schedules
24+
## Service Schedules
2525

2626
Holds the scheduling data for `booking`-type services. Format of `data` is TBD.
2727

2828
```mermaid
2929
erDiagram
30-
schedules {
30+
service_schedules {
3131
uuid id PK
3232
uuid service_id FK
3333
jsonb data "scheduling format TBD"
3434
timestamp created_at
35+
timestamp updated_at
3536
}
3637
```
3738

@@ -51,12 +52,12 @@ erDiagram
5152
timestamp created_at
5253
}
5354
54-
services ||--o| schedules : "has schedule"
55+
services ||--o| service_schedules : "has schedule"
5556
services ||--o{ service_bookings : "booked via"
5657
```
5758

5859
## Notes
5960

6061
- `price` is stored in **cents** (integer) to avoid floating-point issues.
6162
- `is_active = false` hides a service without deleting historical bookings.
62-
- `scheduling_id` is a soft reference to `schedules.id` — cascade is handled from `schedules.service_id → services.id`.
63+
- `scheduling_id` is a soft reference to `service_schedules.id` — cascade is handled from `service_schedules.service_id → services.id`.

docs/webinars.md

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
# Webinars & Webinar Registrations Tables
1+
# Webinars Table
22

3-
## Webinars
4-
5-
Online events that platform members can register for. Two tiers:
6-
- **`free`** — open to all users.
7-
- **`premium`** — restricted access.
3+
Online video content hosted on the platform. Two tiers:
4+
- **`free`** — accessible to all users.
5+
- **`premium`** — accessible to active subscribers only.
86

97
```mermaid
108
erDiagram
@@ -14,22 +12,15 @@ erDiagram
1412
text description
1513
webinar_tier tier "free | premium"
1614
int duration_minutes
17-
text meeting_url
15+
text youtube_url
1816
boolean is_active
1917
timestamp created_at
18+
timestamp updated_at
2019
}
21-
22-
webinar_registrations {
23-
uuid id PK
24-
uuid user_id FK
25-
uuid webinar_id FK
26-
timestamp registered_at
27-
}
28-
29-
webinars ||--o{ webinar_registrations : "has registrations"
3020
```
3121

3222
## Notes
3323

34-
- `meeting_url` can be a Zoom/Google Meet link, added before the event starts.
35-
- `is_active = false` hides a webinar without losing registration history.
24+
- Access is determined by the user's subscription status, not registration — there is no sign-up flow.
25+
- `youtube_url` is the link to the YouTube video.
26+
- `is_active = false` hides a webinar without deleting it.

lib/db/schema.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { pgTable, text, timestamp, uuid, pgEnum, integer, boolean, time, jsonb } from "drizzle-orm/pg-core";
1+
import { pgTable, text, timestamp, uuid, pgEnum, integer, boolean, jsonb } from "drizzle-orm/pg-core";
22

33
export const roleEnum = pgEnum("role", ["user", "admin", "coach"]);
44
export const serviceTypeEnum = pgEnum('service_type', ["coaching_session", "booking"]);
@@ -17,12 +17,14 @@ export const profiles = pgTable("profiles", {
1717
updatedAt: timestamp("updated_at").defaultNow().notNull(),
1818
})
1919

20-
export const schedules = pgTable("schedules", {
20+
export const serviceSchedules = pgTable("service_schedules", {
2121
id: uuid("id").primaryKey().defaultRandom(),
2222
serviceId: uuid("service_id").references(() => services.id, { onDelete: "cascade" }).notNull(),
2323
data: jsonb("data").notNull(),
2424
createdAt: timestamp("created_at").defaultNow().notNull(),
25-
})
25+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
26+
});
27+
2628

2729
export const services = pgTable("services", {
2830
id: uuid("id").primaryKey().defaultRandom(),
@@ -34,6 +36,7 @@ export const services = pgTable("services", {
3436
price: integer("price").notNull().default(0),
3537
isActive: boolean("is_active").notNull().default(true),
3638
createdAt: timestamp("created_at").defaultNow().notNull(),
39+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
3740
})
3841

3942
export const serviceBookings = pgTable("service_bookings", {
@@ -44,6 +47,7 @@ export const serviceBookings = pgTable("service_bookings", {
4447
notes: text("notes"),
4548
isActive: boolean("is_active").notNull().default(true),
4649
createdAt: timestamp("created_at").defaultNow().notNull(),
50+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
4751
});
4852

4953
export const webinars = pgTable("webinars", {
@@ -52,17 +56,10 @@ export const webinars = pgTable("webinars", {
5256
description: text("description"),
5357
tier: webinarTierEnum("tier").notNull().default("free"),
5458
durationMinutes: integer("duration_minutes").notNull(),
55-
meetingUrl: text("meeting_url"),
59+
youtubeUrl: text("youtube_url"),
5660
isActive: boolean("is_active").notNull().default(true),
5761
createdAt: timestamp("created_at").defaultNow().notNull(),
58-
});
59-
60-
61-
export const webinarRegistrations = pgTable("webinar_registrations", {
62-
id: uuid("id").primaryKey().defaultRandom(),
63-
userId: uuid("user_id").references(() => profiles.id, { onDelete: "cascade" }).notNull(),
64-
webinarId: uuid("webinar_id").references(() => webinars.id, { onDelete: "cascade" }).notNull(),
65-
registeredAt: timestamp("registered_at").defaultNow().notNull(),
62+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
6663
});
6764

6865
export const coachingSessions = pgTable("coaching_sessions", {
@@ -75,8 +72,9 @@ export const coachingSessions = pgTable("coaching_sessions", {
7572
status: sessionStatusEnum("status").notNull().default("pending"),
7673
meetingUrl: text("meeting_url"),
7774
notes: text("notes"),
78-
selectedTimeSlots: time("selected_time_slots").array().notNull(),
75+
selectedTimeSlots: jsonb("selected_time_slots").notNull(),
7976
createdAt: timestamp("created_at").defaultNow().notNull(),
77+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
8078
});
8179

8280
export const subscriptions = pgTable("subscriptions", {
@@ -101,4 +99,5 @@ export const purchases = pgTable("purchases", {
10199
amount: integer("amount").notNull(),
102100
currency: text("currency").notNull(),
103101
createdAt: timestamp("created_at").defaultNow().notNull(),
102+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
104103
});

0 commit comments

Comments
 (0)