Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

schema-standup.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

schema-standup.tsBlame76 lines · 1 contributor
a686079Claude1/**
2 * AI Standup — Drizzle schema for the daily/weekly Claude-generated
3 * team-brief feature.
4 *
5 * Defined in a SEPARATE module because `src/db/schema.ts` is listed in
6 * §4 LOCKED BLOCKS of BUILD_BIBLE.md and must not be edited. The matching
7 * migration is `drizzle/0057_ai_standup.sql`.
8 *
9 * Two tables:
10 * - `user_standup_prefs` — per-user opt-in flags. Row missing == opted
11 * out (the lazy-create-on-toggle pattern keeps the legacy user table
12 * untouched).
13 * - `ai_standups` — generated standup records, surfaced at /standups
14 * and used for same-day dedupe.
15 */
16
17import {
18 boolean,
19 index,
20 integer,
21 pgTable,
22 text,
23 timestamp,
24 uuid,
25} from "drizzle-orm/pg-core";
26
27export const userStandupPrefs = pgTable("user_standup_prefs", {
28 userId: uuid("user_id").primaryKey(),
29 dailyEnabled: boolean("daily_enabled").default(false).notNull(),
30 weeklyEnabled: boolean("weekly_enabled").default(false).notNull(),
31 emailEnabled: boolean("email_enabled").default(false).notNull(),
32 hourUtc: integer("hour_utc").default(9).notNull(),
33 lastDailySentAt: timestamp("last_daily_sent_at", { withTimezone: true }),
34 lastWeeklySentAt: timestamp("last_weekly_sent_at", { withTimezone: true }),
35 createdAt: timestamp("created_at", { withTimezone: true })
36 .defaultNow()
37 .notNull(),
38 updatedAt: timestamp("updated_at", { withTimezone: true })
39 .defaultNow()
40 .notNull(),
41});
42
43export type UserStandupPrefsRow = typeof userStandupPrefs.$inferSelect;
44export type NewUserStandupPrefsRow = typeof userStandupPrefs.$inferInsert;
45
46export const aiStandups = pgTable(
47 "ai_standups",
48 {
49 id: uuid("id").primaryKey().defaultRandom(),
50 userId: uuid("user_id").notNull(),
51 // 'daily' | 'weekly'
52 scope: text("scope").notNull(),
53 summary: text("summary").notNull(),
54 // JSON-serialized string arrays so we don't depend on jsonb features.
55 shippedItems: text("shipped_items").default("[]").notNull(),
56 blockedItems: text("blocked_items").default("[]").notNull(),
57 atRiskItems: text("at_risk_items").default("[]").notNull(),
58 windowStart: timestamp("window_start", { withTimezone: true }).notNull(),
59 windowEnd: timestamp("window_end", { withTimezone: true }).notNull(),
60 aiAvailable: boolean("ai_available").default(false).notNull(),
61 createdAt: timestamp("created_at", { withTimezone: true })
62 .defaultNow()
63 .notNull(),
64 },
65 (table) => [
66 index("idx_ai_standups_user_created").on(table.userId, table.createdAt),
67 index("idx_ai_standups_user_scope_created").on(
68 table.userId,
69 table.scope,
70 table.createdAt
71 ),
72 ]
73);
74
75export type AiStandupRow = typeof aiStandups.$inferSelect;
76export type NewAiStandupRow = typeof aiStandups.$inferInsert;