@goscribe/server 1.0.11 → 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.
- package/ANALYSIS_PROGRESS_SPEC.md +463 -0
- package/PROGRESS_QUICK_REFERENCE.md +239 -0
- package/dist/lib/ai-session.d.ts +20 -9
- package/dist/lib/ai-session.js +316 -80
- package/dist/lib/auth.d.ts +35 -2
- package/dist/lib/auth.js +88 -15
- package/dist/lib/env.d.ts +32 -0
- package/dist/lib/env.js +46 -0
- package/dist/lib/errors.d.ts +33 -0
- package/dist/lib/errors.js +78 -0
- package/dist/lib/inference.d.ts +4 -1
- package/dist/lib/inference.js +9 -11
- package/dist/lib/logger.d.ts +62 -0
- package/dist/lib/logger.js +342 -0
- package/dist/lib/podcast-prompts.d.ts +43 -0
- package/dist/lib/podcast-prompts.js +135 -0
- package/dist/lib/pusher.d.ts +1 -0
- package/dist/lib/pusher.js +14 -2
- package/dist/lib/storage.d.ts +3 -3
- package/dist/lib/storage.js +51 -47
- package/dist/lib/validation.d.ts +51 -0
- package/dist/lib/validation.js +64 -0
- package/dist/routers/_app.d.ts +697 -111
- package/dist/routers/_app.js +5 -0
- package/dist/routers/auth.d.ts +11 -1
- package/dist/routers/chat.d.ts +11 -1
- package/dist/routers/flashcards.d.ts +205 -6
- package/dist/routers/flashcards.js +144 -66
- package/dist/routers/members.d.ts +165 -0
- package/dist/routers/members.js +531 -0
- package/dist/routers/podcast.d.ts +78 -63
- package/dist/routers/podcast.js +330 -393
- package/dist/routers/studyguide.d.ts +11 -1
- package/dist/routers/worksheets.d.ts +124 -13
- package/dist/routers/worksheets.js +123 -50
- package/dist/routers/workspace.d.ts +213 -26
- package/dist/routers/workspace.js +303 -181
- package/dist/server.js +12 -4
- package/dist/services/flashcard-progress.service.d.ts +183 -0
- package/dist/services/flashcard-progress.service.js +383 -0
- package/dist/services/flashcard.service.d.ts +183 -0
- package/dist/services/flashcard.service.js +224 -0
- package/dist/services/podcast-segment-reorder.d.ts +0 -0
- package/dist/services/podcast-segment-reorder.js +107 -0
- package/dist/services/podcast.service.d.ts +0 -0
- package/dist/services/podcast.service.js +326 -0
- package/dist/services/worksheet.service.d.ts +0 -0
- package/dist/services/worksheet.service.js +295 -0
- package/dist/trpc.d.ts +13 -2
- package/dist/trpc.js +55 -6
- package/dist/types/index.d.ts +126 -0
- package/dist/types/index.js +1 -0
- package/package.json +3 -2
- package/prisma/schema.prisma +142 -4
- package/src/lib/ai-session.ts +356 -85
- package/src/lib/auth.ts +113 -19
- package/src/lib/env.ts +59 -0
- package/src/lib/errors.ts +92 -0
- package/src/lib/inference.ts +11 -11
- package/src/lib/logger.ts +405 -0
- package/src/lib/pusher.ts +15 -3
- package/src/lib/storage.ts +56 -51
- package/src/lib/validation.ts +75 -0
- package/src/routers/_app.ts +5 -0
- package/src/routers/chat.ts +2 -23
- package/src/routers/flashcards.ts +108 -24
- package/src/routers/members.ts +586 -0
- package/src/routers/podcast.ts +385 -420
- package/src/routers/worksheets.ts +118 -36
- package/src/routers/workspace.ts +356 -195
- package/src/server.ts +13 -4
- package/src/services/flashcard-progress.service.ts +541 -0
- package/src/trpc.ts +59 -6
- package/src/types/index.ts +165 -0
- package/AUTH_FRONTEND_SPEC.md +0 -21
- package/CHAT_FRONTEND_SPEC.md +0 -474
- package/DATABASE_SETUP.md +0 -165
- package/MEETINGSUMMARY_FRONTEND_SPEC.md +0 -28
- package/PODCAST_FRONTEND_SPEC.md +0 -595
- package/STUDYGUIDE_FRONTEND_SPEC.md +0 -18
- package/WORKSHEETS_FRONTEND_SPEC.md +0 -26
- package/WORKSPACE_FRONTEND_SPEC.md +0 -47
- package/test-ai-integration.js +0 -134
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type { Prisma } from '@prisma/client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Common types for the application
|
|
5
|
+
*/
|
|
6
|
+
export type PrismaTransaction = Omit<
|
|
7
|
+
Prisma.TransactionClient,
|
|
8
|
+
'$connect' | '$disconnect' | '$on' | '$transaction' | '$use'
|
|
9
|
+
>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* User types
|
|
13
|
+
*/
|
|
14
|
+
export interface UserSession {
|
|
15
|
+
id: string;
|
|
16
|
+
name?: string | null;
|
|
17
|
+
email?: string | null;
|
|
18
|
+
image?: string | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface AuthContext {
|
|
22
|
+
session: {
|
|
23
|
+
user: UserSession;
|
|
24
|
+
} | null;
|
|
25
|
+
userId?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Artifact types
|
|
30
|
+
*/
|
|
31
|
+
export type ArtifactTypeEnum =
|
|
32
|
+
| 'STUDY_GUIDE'
|
|
33
|
+
| 'FLASHCARD_SET'
|
|
34
|
+
| 'WORKSHEET'
|
|
35
|
+
| 'MEETING_SUMMARY'
|
|
36
|
+
| 'PODCAST_EPISODE';
|
|
37
|
+
|
|
38
|
+
export type DifficultyEnum = 'EASY' | 'MEDIUM' | 'HARD';
|
|
39
|
+
|
|
40
|
+
export type QuestionTypeEnum =
|
|
41
|
+
| 'MULTIPLE_CHOICE'
|
|
42
|
+
| 'TEXT'
|
|
43
|
+
| 'NUMERIC'
|
|
44
|
+
| 'TRUE_FALSE'
|
|
45
|
+
| 'MATCHING'
|
|
46
|
+
| 'FILL_IN_THE_BLANK';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Worksheet types
|
|
50
|
+
*/
|
|
51
|
+
// Base mark scheme stored in question meta
|
|
52
|
+
export interface MarkSchemePoint {
|
|
53
|
+
point: number;
|
|
54
|
+
requirements: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface MarkScheme {
|
|
58
|
+
points: MarkSchemePoint[];
|
|
59
|
+
totalPoints: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// User progress mark scheme with achieved points and feedback
|
|
63
|
+
export interface UserMarkSchemePoint extends MarkSchemePoint {
|
|
64
|
+
achievedPoints: number;
|
|
65
|
+
feedback: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface UserMarkScheme {
|
|
69
|
+
points: UserMarkSchemePoint[];
|
|
70
|
+
totalPoints: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface WorksheetQuestionMeta {
|
|
74
|
+
options?: string[];
|
|
75
|
+
completed?: boolean;
|
|
76
|
+
userAnswer?: string;
|
|
77
|
+
completedAt?: Date | null;
|
|
78
|
+
mark_scheme?: MarkScheme;
|
|
79
|
+
userMarkScheme?: UserMarkScheme; // Merged from progress
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface WorksheetQuestionProgressMeta {
|
|
83
|
+
userMarkScheme?: UserMarkScheme;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface CreateWorksheetQuestionInput {
|
|
87
|
+
prompt: string;
|
|
88
|
+
answer?: string;
|
|
89
|
+
type: QuestionTypeEnum;
|
|
90
|
+
difficulty?: DifficultyEnum;
|
|
91
|
+
order?: number;
|
|
92
|
+
meta?: WorksheetQuestionMeta;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface UpdateWorksheetQuestionInput extends Partial<CreateWorksheetQuestionInput> {
|
|
96
|
+
id: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Flashcard types
|
|
101
|
+
*/
|
|
102
|
+
export interface CreateFlashcardInput {
|
|
103
|
+
front: string;
|
|
104
|
+
back: string;
|
|
105
|
+
tags?: string[];
|
|
106
|
+
order?: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface UpdateFlashcardInput extends Partial<CreateFlashcardInput> {
|
|
110
|
+
id: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* File upload types
|
|
115
|
+
*/
|
|
116
|
+
export interface FileUploadResult {
|
|
117
|
+
id: string;
|
|
118
|
+
name: string;
|
|
119
|
+
url: string;
|
|
120
|
+
mimeType: string;
|
|
121
|
+
size: number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Pagination types
|
|
126
|
+
*/
|
|
127
|
+
export interface PaginationInput {
|
|
128
|
+
page?: number;
|
|
129
|
+
limit?: number;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface PaginatedResult<T> {
|
|
133
|
+
data: T[];
|
|
134
|
+
pagination: {
|
|
135
|
+
page: number;
|
|
136
|
+
limit: number;
|
|
137
|
+
total: number;
|
|
138
|
+
totalPages: number;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Search types
|
|
144
|
+
*/
|
|
145
|
+
export interface SearchInput extends PaginationInput {
|
|
146
|
+
query: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Response types
|
|
151
|
+
*/
|
|
152
|
+
export type SuccessResponse<T = void> = {
|
|
153
|
+
success: true;
|
|
154
|
+
data: T;
|
|
155
|
+
message?: string;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export type ErrorResponse = {
|
|
159
|
+
success: false;
|
|
160
|
+
error: {
|
|
161
|
+
code: string;
|
|
162
|
+
message: string;
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
|
package/AUTH_FRONTEND_SPEC.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
## Auth Frontend Spec
|
|
2
|
-
|
|
3
|
-
### Endpoints (tRPC)
|
|
4
|
-
- **auth.signup**: `{ name: string; email: string; password: string }` → `{ id: string; email: string; name: string }`
|
|
5
|
-
- **auth.login**: `{ email: string; password: string }` → `{ id: string; email: string; name: string; image?: string | null; token: string }` (also sets `auth_token` cookie)
|
|
6
|
-
- **auth.getSession**: `void` → `{ user: { id: string; email: string; name: string; image?: string | null } }`
|
|
7
|
-
- **auth.logout**: `void` → `{ success: true }` (clears `auth_token` cookie)
|
|
8
|
-
|
|
9
|
-
### Cookie & Token
|
|
10
|
-
- On login, server sets `auth_token` cookie (HTTP-only). Value is HMAC of base64 user id with `AUTH_SECRET`.
|
|
11
|
-
- Cookie attributes:
|
|
12
|
-
- `httpOnly: true`
|
|
13
|
-
- `secure: true` in production
|
|
14
|
-
- `sameSite: 'none'` in production, `'lax'` in dev
|
|
15
|
-
- `domain: 'server-w8mz.onrender.com'` in production
|
|
16
|
-
- `maxAge: 30 days`
|
|
17
|
-
|
|
18
|
-
### UX Notes
|
|
19
|
-
- After `auth.login`, rely on cookie for session; also keep returned `token` if needed for client-side display.
|
|
20
|
-
- Call `auth.getSession` on app bootstrap; if it throws, redirect to login.
|
|
21
|
-
- On `auth.logout`, clear local user state immediately (optimistic) and navigate to login.
|
package/CHAT_FRONTEND_SPEC.md
DELETED
|
@@ -1,474 +0,0 @@
|
|
|
1
|
-
# Chat Frontend Integration Specification
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
This document outlines the frontend requirements for integrating with the chat functionality, including real-time messaging, channel management, and user interactions.
|
|
5
|
-
|
|
6
|
-
## Real-Time Events (Pusher)
|
|
7
|
-
|
|
8
|
-
### Event Channels
|
|
9
|
-
Chat events are broadcast on different channels:
|
|
10
|
-
- Channel events: `workspace_{workspaceId}`
|
|
11
|
-
- Message events: `{channelId}` (the channelId itself is used as the channel name)
|
|
12
|
-
|
|
13
|
-
### Event Types
|
|
14
|
-
|
|
15
|
-
#### 1. Channel Management Events
|
|
16
|
-
```typescript
|
|
17
|
-
// New Channel Created
|
|
18
|
-
{
|
|
19
|
-
event: '{workspaceId}_new_channel',
|
|
20
|
-
data: {
|
|
21
|
-
channelId: string,
|
|
22
|
-
workspaceId: string,
|
|
23
|
-
name: string,
|
|
24
|
-
createdAt: string
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Channel Edited
|
|
29
|
-
{
|
|
30
|
-
event: '{workspaceId}_edit_channel',
|
|
31
|
-
data: {
|
|
32
|
-
channelId: string,
|
|
33
|
-
workspaceId: string,
|
|
34
|
-
name: string
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Channel Removed
|
|
39
|
-
{
|
|
40
|
-
event: '{workspaceId}_remove_channel',
|
|
41
|
-
data: {
|
|
42
|
-
channelId: string,
|
|
43
|
-
deletedAt: string
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
#### 2. Message Events
|
|
49
|
-
```typescript
|
|
50
|
-
// New Message Posted
|
|
51
|
-
{
|
|
52
|
-
event: '{channelId}_new_message',
|
|
53
|
-
data: {
|
|
54
|
-
chatId: string,
|
|
55
|
-
channelId: string,
|
|
56
|
-
userId: string,
|
|
57
|
-
message: string,
|
|
58
|
-
createdAt: string
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Message Edited
|
|
63
|
-
{
|
|
64
|
-
event: '{channelId}_edit_message',
|
|
65
|
-
data: {
|
|
66
|
-
chatId: string,
|
|
67
|
-
channelId: string,
|
|
68
|
-
userId: string,
|
|
69
|
-
message: string,
|
|
70
|
-
updatedAt: string
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Message Deleted
|
|
75
|
-
{
|
|
76
|
-
event: '{channelId}_delete_message',
|
|
77
|
-
data: {
|
|
78
|
-
chatId: string,
|
|
79
|
-
channelId: string,
|
|
80
|
-
userId: string,
|
|
81
|
-
deletedAt: string
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Data Types
|
|
87
|
-
|
|
88
|
-
### Channel
|
|
89
|
-
```typescript
|
|
90
|
-
interface Channel {
|
|
91
|
-
id: string;
|
|
92
|
-
workspaceId: string;
|
|
93
|
-
name: string;
|
|
94
|
-
createdAt: string;
|
|
95
|
-
updatedAt: string;
|
|
96
|
-
chats?: ChatMessage[]; // Includes user information for each message
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Chat Message
|
|
101
|
-
```typescript
|
|
102
|
-
interface ChatMessage {
|
|
103
|
-
id: string;
|
|
104
|
-
channelId: string;
|
|
105
|
-
userId: string;
|
|
106
|
-
message: string;
|
|
107
|
-
createdAt: string;
|
|
108
|
-
updatedAt: string;
|
|
109
|
-
user: {
|
|
110
|
-
id: string;
|
|
111
|
-
name: string;
|
|
112
|
-
image?: string;
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### User Information
|
|
118
|
-
All messages include user information with:
|
|
119
|
-
- `id`: User ID
|
|
120
|
-
- `name`: User display name
|
|
121
|
-
- `image`: User avatar (optional)
|
|
122
|
-
|
|
123
|
-
## API Endpoints
|
|
124
|
-
|
|
125
|
-
### 1. Get Channels
|
|
126
|
-
```typescript
|
|
127
|
-
// GET /trpc/chat.getChannels
|
|
128
|
-
{
|
|
129
|
-
input: {
|
|
130
|
-
workspaceId: string;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// Returns all channels for a workspace with messages and user info
|
|
134
|
-
// Creates "General" channel if no channels exist
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 2. Get Channel
|
|
138
|
-
```typescript
|
|
139
|
-
// GET /trpc/chat.getChannel
|
|
140
|
-
{
|
|
141
|
-
input: {
|
|
142
|
-
workspaceId?: string;
|
|
143
|
-
channelId?: string;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
// Returns specific channel with messages and user info
|
|
147
|
-
// Creates "General" channel if workspaceId provided and no channelId
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### 3. Create Channel
|
|
151
|
-
```typescript
|
|
152
|
-
// POST /trpc/chat.createChannel
|
|
153
|
-
{
|
|
154
|
-
input: {
|
|
155
|
-
workspaceId: string;
|
|
156
|
-
name: string;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
// Creates new channel and returns with messages and user info
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### 4. Edit Channel
|
|
163
|
-
```typescript
|
|
164
|
-
// POST /trpc/chat.editChannel
|
|
165
|
-
{
|
|
166
|
-
input: {
|
|
167
|
-
workspaceId: string;
|
|
168
|
-
channelId: string;
|
|
169
|
-
name: string;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
// Updates channel name and returns with messages and user info
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### 5. Remove Channel
|
|
176
|
-
```typescript
|
|
177
|
-
// POST /trpc/chat.removeChannel
|
|
178
|
-
{
|
|
179
|
-
input: {
|
|
180
|
-
workspaceId: string;
|
|
181
|
-
channelId: string;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
// Deletes channel and returns { success: true }
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### 6. Post Message
|
|
188
|
-
```typescript
|
|
189
|
-
// POST /trpc/chat.postMessage
|
|
190
|
-
{
|
|
191
|
-
input: {
|
|
192
|
-
channelId: string;
|
|
193
|
-
message: string;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
// Creates new message and returns with user info
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### 7. Edit Message
|
|
200
|
-
```typescript
|
|
201
|
-
// POST /trpc/chat.editMessage
|
|
202
|
-
{
|
|
203
|
-
input: {
|
|
204
|
-
chatId: string;
|
|
205
|
-
message: string;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
// Updates message and returns with user info
|
|
209
|
-
// Only allows editing own messages
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### 8. Delete Message
|
|
213
|
-
```typescript
|
|
214
|
-
// POST /trpc/chat.deleteMessage
|
|
215
|
-
{
|
|
216
|
-
input: {
|
|
217
|
-
chatId: string;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
// Deletes message and returns { success: true }
|
|
221
|
-
// Only allows deleting own messages
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## UI Components
|
|
225
|
-
|
|
226
|
-
### 1. Channel List Component
|
|
227
|
-
```typescript
|
|
228
|
-
interface ChannelList {
|
|
229
|
-
channels: Channel[];
|
|
230
|
-
currentChannelId?: string;
|
|
231
|
-
onChannelSelect: (channelId: string) => void;
|
|
232
|
-
onCreateChannel: (name: string) => void;
|
|
233
|
-
onEditChannel: (channelId: string, name: string) => void;
|
|
234
|
-
onDeleteChannel: (channelId: string) => void;
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### 2. Chat Interface Component
|
|
239
|
-
```typescript
|
|
240
|
-
interface ChatInterface {
|
|
241
|
-
channelId: string;
|
|
242
|
-
messages: ChatMessage[];
|
|
243
|
-
currentUserId: string;
|
|
244
|
-
onSendMessage: (message: string) => void;
|
|
245
|
-
onEditMessage: (chatId: string, message: string) => void;
|
|
246
|
-
onDeleteMessage: (chatId: string) => void;
|
|
247
|
-
isLoading: boolean;
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### 3. Message Component
|
|
252
|
-
```typescript
|
|
253
|
-
interface MessageComponent {
|
|
254
|
-
message: ChatMessage;
|
|
255
|
-
isOwnMessage: boolean;
|
|
256
|
-
onEdit: (chatId: string, newMessage: string) => void;
|
|
257
|
-
onDelete: (chatId: string) => void;
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
## User Experience Flow
|
|
262
|
-
|
|
263
|
-
### 1. Channel Management
|
|
264
|
-
1. User opens workspace
|
|
265
|
-
2. Load all channels using `getChannels` endpoint
|
|
266
|
-
3. System automatically creates "General" channel if no channels exist
|
|
267
|
-
4. User can create new channels
|
|
268
|
-
5. User can edit channel names
|
|
269
|
-
6. User can delete channels (with confirmation)
|
|
270
|
-
7. Real-time updates when channels are created/edited/deleted
|
|
271
|
-
|
|
272
|
-
### 2. Messaging Flow
|
|
273
|
-
1. User selects a channel
|
|
274
|
-
2. Load existing messages for the channel (includes user info)
|
|
275
|
-
3. User types and sends message
|
|
276
|
-
4. Message appears immediately (optimistic update)
|
|
277
|
-
5. Real-time notification to other users
|
|
278
|
-
6. Handle message editing and deletion
|
|
279
|
-
7. Show user names and avatars for all messages
|
|
280
|
-
|
|
281
|
-
### 3. Message Management
|
|
282
|
-
1. User can edit their own messages only
|
|
283
|
-
2. User can delete their own messages only
|
|
284
|
-
3. Real-time updates for message changes
|
|
285
|
-
4. Proper error handling for unauthorized actions
|
|
286
|
-
|
|
287
|
-
## Real-Time Implementation
|
|
288
|
-
|
|
289
|
-
### PusherService Methods
|
|
290
|
-
The chat system uses two different PusherService methods:
|
|
291
|
-
- `emitTaskComplete(workspaceId, event, data)` - For channel management events
|
|
292
|
-
- `emitChannelEvent(channelId, event, data)` - For message events (channel-specific)
|
|
293
|
-
|
|
294
|
-
### 1. Initial Channel Loading
|
|
295
|
-
```typescript
|
|
296
|
-
// Load all channels for a workspace
|
|
297
|
-
const channels = await trpc.chat.getChannels.query({
|
|
298
|
-
workspaceId: workspaceId
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// This will automatically create a "General" channel if none exist
|
|
302
|
-
// All channels include messages with user information
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### 2. Channel Events (Workspace Channel)
|
|
306
|
-
```typescript
|
|
307
|
-
// Subscribe to workspace channel events
|
|
308
|
-
const workspaceChannel = pusher.subscribe(`workspace_${workspaceId}`);
|
|
309
|
-
|
|
310
|
-
workspaceChannel.bind(`${workspaceId}_new_channel`, (data) => {
|
|
311
|
-
// Add new channel to list
|
|
312
|
-
setChannels(prev => [...prev, data]);
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
workspaceChannel.bind(`${workspaceId}_edit_channel`, (data) => {
|
|
316
|
-
// Update channel name in list
|
|
317
|
-
setChannels(prev => prev.map(ch =>
|
|
318
|
-
ch.id === data.channelId ? { ...ch, name: data.name } : ch
|
|
319
|
-
));
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
workspaceChannel.bind(`${workspaceId}_remove_channel`, (data) => {
|
|
323
|
-
// Remove channel from list
|
|
324
|
-
setChannels(prev => prev.filter(ch => ch.id !== data.channelId));
|
|
325
|
-
});
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
### 3. Message Events (Channel-Specific)
|
|
329
|
-
```typescript
|
|
330
|
-
// Subscribe to message events for specific channel
|
|
331
|
-
const messageChannel = pusher.subscribe(channelId);
|
|
332
|
-
|
|
333
|
-
messageChannel.bind(`${channelId}_new_message`, (data) => {
|
|
334
|
-
// Add new message to chat
|
|
335
|
-
setMessages(prev => [...prev, data]);
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
messageChannel.bind(`${channelId}_edit_message`, (data) => {
|
|
339
|
-
// Update message in chat
|
|
340
|
-
setMessages(prev => prev.map(msg =>
|
|
341
|
-
msg.id === data.chatId ? { ...msg, message: data.message, updatedAt: data.updatedAt } : msg
|
|
342
|
-
));
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
messageChannel.bind(`${channelId}_delete_message`, (data) => {
|
|
346
|
-
// Remove message from chat
|
|
347
|
-
setMessages(prev => prev.filter(msg => msg.id !== data.chatId));
|
|
348
|
-
});
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
## Error Handling
|
|
352
|
-
|
|
353
|
-
### 1. Channel Errors
|
|
354
|
-
- Channel not found
|
|
355
|
-
- Unauthorized to edit/delete channel
|
|
356
|
-
- Duplicate channel names
|
|
357
|
-
|
|
358
|
-
### 2. Message Errors
|
|
359
|
-
- Message not found
|
|
360
|
-
- Unauthorized to edit/delete message (only own messages)
|
|
361
|
-
- Message too long
|
|
362
|
-
- Rate limiting
|
|
363
|
-
|
|
364
|
-
### 3. Network Errors
|
|
365
|
-
- Connection lost
|
|
366
|
-
- Retry logic for failed operations
|
|
367
|
-
- Offline indicators
|
|
368
|
-
|
|
369
|
-
## Loading States
|
|
370
|
-
|
|
371
|
-
### 1. Channel Loading
|
|
372
|
-
```typescript
|
|
373
|
-
interface ChannelLoadingState {
|
|
374
|
-
isLoading: boolean;
|
|
375
|
-
error?: string;
|
|
376
|
-
channels: Channel[];
|
|
377
|
-
}
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
### 2. Message Loading
|
|
381
|
-
```typescript
|
|
382
|
-
interface MessageLoadingState {
|
|
383
|
-
isLoading: boolean;
|
|
384
|
-
isSending: boolean;
|
|
385
|
-
error?: string;
|
|
386
|
-
messages: ChatMessage[];
|
|
387
|
-
}
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
## Security & Authorization
|
|
391
|
-
|
|
392
|
-
### 1. Message Ownership
|
|
393
|
-
- Users can only edit their own messages
|
|
394
|
-
- Users can only delete their own messages
|
|
395
|
-
- Proper validation on server side
|
|
396
|
-
|
|
397
|
-
### 2. Channel Access
|
|
398
|
-
- Users can only access channels in their workspaces
|
|
399
|
-
- Proper workspace membership validation
|
|
400
|
-
|
|
401
|
-
### 3. Input Validation
|
|
402
|
-
- Message content validation
|
|
403
|
-
- Channel name validation
|
|
404
|
-
- Rate limiting for message sending
|
|
405
|
-
|
|
406
|
-
## Performance Considerations
|
|
407
|
-
|
|
408
|
-
### 1. Message Loading
|
|
409
|
-
- All messages include user info (no additional queries needed)
|
|
410
|
-
- Efficient database queries with includes
|
|
411
|
-
- Proper indexing on channelId and userId
|
|
412
|
-
|
|
413
|
-
### 2. Real-time Updates
|
|
414
|
-
- Separate channels for workspace and message events
|
|
415
|
-
- Efficient event routing
|
|
416
|
-
- Optimized payload sizes
|
|
417
|
-
|
|
418
|
-
### 3. Memory Management
|
|
419
|
-
- Clean up Pusher subscriptions when switching channels
|
|
420
|
-
- Limit message history in memory
|
|
421
|
-
- Garbage collection for old messages
|
|
422
|
-
|
|
423
|
-
## Testing Requirements
|
|
424
|
-
|
|
425
|
-
### 1. Unit Tests
|
|
426
|
-
- Component rendering with user info
|
|
427
|
-
- Message formatting and display
|
|
428
|
-
- Channel management logic
|
|
429
|
-
|
|
430
|
-
### 2. Integration Tests
|
|
431
|
-
- API interactions with user data
|
|
432
|
-
- Real-time event handling
|
|
433
|
-
- Authorization scenarios
|
|
434
|
-
|
|
435
|
-
### 3. E2E Tests
|
|
436
|
-
- Complete messaging flow with user attribution
|
|
437
|
-
- Channel management
|
|
438
|
-
- Real-time synchronization
|
|
439
|
-
|
|
440
|
-
## Browser Support
|
|
441
|
-
|
|
442
|
-
### Required
|
|
443
|
-
- Chrome 90+
|
|
444
|
-
- Firefox 88+
|
|
445
|
-
- Safari 14+
|
|
446
|
-
- Edge 90+
|
|
447
|
-
|
|
448
|
-
### Real-time Support
|
|
449
|
-
- WebSocket support
|
|
450
|
-
- Pusher client compatibility
|
|
451
|
-
- EventSource fallback
|
|
452
|
-
|
|
453
|
-
## Future Enhancements
|
|
454
|
-
|
|
455
|
-
### 1. Advanced Features
|
|
456
|
-
- Message reactions
|
|
457
|
-
- File attachments
|
|
458
|
-
- Voice messages
|
|
459
|
-
- Message threading
|
|
460
|
-
- Read receipts
|
|
461
|
-
|
|
462
|
-
### 2. UI Improvements
|
|
463
|
-
- Typing indicators
|
|
464
|
-
- Message search
|
|
465
|
-
- Message pinning
|
|
466
|
-
- Channel categories
|
|
467
|
-
- Dark mode support
|
|
468
|
-
|
|
469
|
-
### 3. Performance Optimizations
|
|
470
|
-
- Message pagination
|
|
471
|
-
- Virtual scrolling
|
|
472
|
-
- Offline support
|
|
473
|
-
- Background sync
|
|
474
|
-
- Push notifications
|