Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 39x 39x 39x 39x 39x 2x 2x 2x 2x | import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'
import { players } from './players'
import { sessionPlans } from './session-plans'
/**
* Shareable observation links for practice sessions
*
* Allows parents/teachers to share time-limited links that anyone can use
* to observe a student's practice session without logging in.
*/
export const sessionObservationShares = sqliteTable(
'session_observation_shares',
{
// 10-char base62 token (cryptographically random)
id: text('id').primaryKey(),
// Session being shared
sessionId: text('session_id')
.notNull()
.references(() => sessionPlans.id, { onDelete: 'cascade' }),
// Player being observed (denormalized for fast lookup)
playerId: text('player_id')
.notNull()
.references(() => players.id, { onDelete: 'cascade' }),
// Who created the share link
createdBy: text('created_by').notNull(),
// Timestamps
createdAt: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
// Status: active, expired (time-based), or revoked (manually)
status: text('status', {
enum: ['active', 'expired', 'revoked'],
})
.notNull()
.default('active'),
// Analytics
viewCount: integer('view_count').notNull().default(0),
lastViewedAt: integer('last_viewed_at', { mode: 'timestamp' }),
},
(table) => ({
// Index for cleanup when session ends
sessionIdx: index('idx_session_observation_shares_session').on(table.sessionId),
// Index for listing active shares
statusIdx: index('idx_session_observation_shares_status').on(table.status),
})
)
export type SessionObservationShare = typeof sessionObservationShares.$inferSelect
export type NewSessionObservationShare = typeof sessionObservationShares.$inferInsert
|