File size: 4,699 Bytes
4554903
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# TypeScript Patterns for Multiverse Campus

## Express Route Pattern (with auth)
```typescript
import { Router } from 'express';
import { requireAuth, requireAdmin } from '../middleware/auth';

const router = Router();

// All routes require auth unless explicitly public
router.use(requireAuth);

router.get('/resource', async (req, res) => {
  try {
    const result = await service.getResource(req.user.studentId);
    res.json({ success: true, data: result });
  } catch (err) {
    res.status(500).json({ success: false, error: err.message });
  }
});

// Admin routes
router.put('/resource/:id', requireAdmin, async (req, res) => { ... });
```

## Zustand Store Pattern
```typescript
import { create } from 'zustand';

interface ResourceStore {
  items: Resource[];
  loading: boolean;
  error: string | null;
  fetch: () => Promise<void>;
  update: (id: string, data: Partial<Resource>) => void;
}

export const useResourceStore = create<ResourceStore>((set, get) => ({
  items: [],
  loading: false,
  error: null,
  fetch: async () => {
    set({ loading: true, error: null });
    try {
      const res = await api.get('/resource');
      set({ items: res.data, loading: false });
    } catch (err) {
      set({ error: err.message, loading: false });
    }
  },
  update: (id, data) => {
    set(state => ({
      items: state.items.map(item =>
        item.id === id ? { ...item, ...data } : item
      ),
    }));
  },
}));
```

## Socket.IO Handler Pattern (server, PM2 cluster-safe)
```typescript
export function registerHandlers(io: Server, socket: AuthenticatedSocket) {
  socket.on('resource:action', async (payload, callback) => {
    try {
      // Validate payload
      const { resourceId } = validatePayload(payload);
      
      // Perform action
      const result = await service.performAction(socket.userId, resourceId);
      
      // Broadcast to room (Redis adapter handles cross-process)
      io.to(`resource:${resourceId}`).emit('resource:updated', result);
      
      // Acknowledge to sender
      callback({ success: true, data: result });
    } catch (err) {
      callback({ success: false, error: err.message });
    }
  });
}
```

## Database Transaction Pattern (pg-boss safe)
```typescript
import { getPool } from '../db';

async function transferGems(fromId: string, toId: string, amount: number) {
  const pool = getPool();
  const client = await pool.connect();
  
  try {
    await client.query('BEGIN');
    
    // Debit
    const debit = await client.query(
      'UPDATE students SET gems = gems - $1 WHERE id = $2 AND gems >= $1 RETURNING gems',
      [amount, fromId]
    );
    if (debit.rowCount === 0) throw new Error('Insufficient gems');
    
    // Credit
    await client.query(
      'UPDATE students SET gems = gems + $1 WHERE id = $2',
      [amount, toId]
    );
    
    await client.query('COMMIT');
  } catch (err) {
    await client.query('ROLLBACK');
    throw err;
  } finally {
    client.release();
  }
}
```

## Migration Pattern (additive only)
```typescript
// migrations/YYYYMMDDHHMMSS_add_feature_column.ts
import { Knex } from 'knex';

export async function up(knex: Knex): Promise<void> {
  await knex.schema.alterTable('students', table => {
    table.timestamp('last_login_at').nullable().defaultTo(null);
    table.index('last_login_at'); // Only if frequently queried
  });
}

export async function down(knex: Knex): Promise<void> {
  await knex.schema.alterTable('students', table => {
    table.dropColumn('last_login_at');
  });
}
// NOTE: down() exists for dev rollback only.
// In production, prefer a NEW migration that deprecates rather than drops.
```

## Error Handling Pattern
```typescript
// Custom error classes for typed error handling
class AppError extends Error {
  constructor(
    message: string,
    public statusCode: number = 500,
    public code: string = 'INTERNAL_ERROR'
  ) {
    super(message);
  }
}

class NotFoundError extends AppError {
  constructor(resource: string, id: string) {
    super(`${resource} ${id} not found`, 404, 'NOT_FOUND');
  }
}

class AuthorizationError extends AppError {
  constructor(action: string) {
    super(`Not authorized to ${action}`, 403, 'FORBIDDEN');
  }
}

// Express error middleware
function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {
  if (err instanceof AppError) {
    return res.status(err.statusCode).json({
      success: false,
      error: { code: err.code, message: err.message },
    });
  }
  // Unknown errors — log and return generic
  console.error('Unhandled error:', err);
  res.status(500).json({ success: false, error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' } });
}
```