@nexttylabs/echo 0.3.0 → 0.5.0

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.
Files changed (248) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/app/(public)/[organizationSlug]/roadmap/page.tsx +19 -1
  3. package/app/api/admin/backup/route.ts +22 -4
  4. package/app/api/auth/register/handler.ts +1 -2
  5. package/lib/auth/config.ts +0 -7
  6. package/lib/db/migrations/0000_needy_leech.sql +335 -0
  7. package/lib/db/migrations/meta/0000_snapshot.json +2186 -1
  8. package/lib/db/migrations/meta/_journal.json +2 -135
  9. package/lib/db/schema/auth.ts +0 -1
  10. package/lib/db/schema/index.ts +0 -1
  11. package/lib/portal/public-context.tsx +5 -0
  12. package/package.json +20 -1
  13. package/.changeset/README.md +0 -21
  14. package/.changeset/config.json +0 -11
  15. package/.changeset/cozy-ghosts-care.md +0 -5
  16. package/.changeset/sharp-lines-stand.md +0 -5
  17. package/.changeset/sour-doodles-eat.md +0 -5
  18. package/.changeset/tender-moose-shop.md +0 -5
  19. package/.github/pull_request_template.md +0 -13
  20. package/.github/workflows/ci.yml +0 -41
  21. package/.github/workflows/publish.yml +0 -44
  22. package/.github/workflows/release.yml +0 -73
  23. package/AGENTS.md +0 -92
  24. package/Dockerfile +0 -57
  25. package/Makefile +0 -77
  26. package/app/api/internal/domain-lookup/route.ts +0 -67
  27. package/bun.lock +0 -2503
  28. package/components/portal/project-switcher.tsx +0 -20
  29. package/docker-compose.dev.yml +0 -26
  30. package/docker-compose.yml +0 -98
  31. package/docs/architecture.md +0 -259
  32. package/docs/component-inventory.md +0 -261
  33. package/docs/database-migrations.md +0 -76
  34. package/docs/development-guide.md +0 -209
  35. package/docs/e2e-user-flows.csv +0 -31
  36. package/docs/er-diagram-feedback.mmd +0 -138
  37. package/docs/er-diagram.mmd +0 -281
  38. package/docs/i18n-check-report.md +0 -296
  39. package/docs/index.md +0 -214
  40. package/docs/logic-chain.md +0 -94
  41. package/docs/plans/2026-01-02-database-migration-scripts.md +0 -496
  42. package/docs/plans/2026-01-02-user-login-design.md +0 -37
  43. package/docs/plans/2026-01-02-user-login.md +0 -437
  44. package/docs/plans/2026-01-02-user-registration-design.md +0 -47
  45. package/docs/plans/2026-01-02-user-registration.md +0 -628
  46. package/docs/plans/2026-01-03-roles-permissions-design.md +0 -20
  47. package/docs/plans/2026-01-03-roles-permissions.md +0 -266
  48. package/docs/plans/2026-01-05-authentication-middleware.md +0 -207
  49. package/docs/plans/2026-01-05-member-removal.md +0 -186
  50. package/docs/plans/2026-01-05-organization-creation.md +0 -374
  51. package/docs/plans/2026-01-05-rbac-middleware.md +0 -112
  52. package/docs/plans/2026-01-05-role-configuration.md +0 -441
  53. package/docs/plans/2026-01-06-file-upload-support.md +0 -804
  54. package/docs/plans/2026-01-06-permission-check-hook.md +0 -155
  55. package/docs/plans/2026-01-06-resource-ownership-check.md +0 -231
  56. package/docs/plans/2026-01-07-feedback-tracking-link.md +0 -459
  57. package/docs/plans/2026-01-09-logout-redirect-design.md +0 -52
  58. package/docs/plans/2026-01-09-phase2-3-plan.md +0 -654
  59. package/docs/plans/2026-01-09-portal-execution-plan.md +0 -408
  60. package/docs/plans/2026-01-09-project-delete-feature-design.md +0 -163
  61. package/docs/plans/2026-01-09-project-delete-implementation.md +0 -451
  62. package/docs/plans/2026-01-09-project-edit-delete-design.md +0 -52
  63. package/docs/plans/2026-01-09-settings-center-design.md +0 -114
  64. package/docs/plans/2026-01-09-settings-center.md +0 -948
  65. package/docs/plans/2026-01-10-organization-only-design.md +0 -66
  66. package/docs/plans/2026-01-10-organization-only-implementation.md +0 -433
  67. package/docs/plans/2026-01-10-portal-settings-restructure-plan.md +0 -18
  68. package/docs/plans/2026-01-10-project-settings-tabs-design-implementation.md +0 -296
  69. package/docs/plans/2026-01-14-e2e-playwright-feedback.md +0 -173
  70. package/docs/plans/2026-01-15-feedback-management-org-context-design.md +0 -82
  71. package/docs/plans/2026-01-15-feedback-management-org-context-implementation-plan.md +0 -521
  72. package/docs/plans/2026-01-16-admin-feedback-filters-design.md +0 -75
  73. package/docs/plans/2026-01-16-admin-feedback-filters-implementation.md +0 -293
  74. package/docs/plans/2026-01-16-admin-feedback-route-consolidation.md +0 -180
  75. package/docs/plans/2026-01-16-e2e-test-fixes.md +0 -158
  76. package/docs/plans/2026-01-17-admin-feedback-filters.md +0 -214
  77. package/docs/plans/2026-01-17-admin-feedback-improvements.md +0 -453
  78. package/docs/plans/2026-01-18-changesets-design.md +0 -40
  79. package/docs/product_changes.md +0 -37
  80. package/docs/project-overview.md +0 -159
  81. package/docs/project-scan-report.json +0 -104
  82. package/docs/route-role-visibility.md +0 -51
  83. package/docs/source-tree-analysis.md +0 -150
  84. package/docs/testing/delete-project-manual-tests.md +0 -18
  85. package/docs/user-story-tracking.md +0 -191
  86. package/eslint.config.mjs +0 -19
  87. package/lib/db/migrations/.gitkeep +0 -0
  88. package/lib/db/migrations/0000_cynical_gladiator.sql +0 -53
  89. package/lib/db/migrations/0001_wandering_sunfire.sql +0 -27
  90. package/lib/db/migrations/0002_shallow_speedball.sql +0 -1
  91. package/lib/db/migrations/0003_add_org_description.sql +0 -1
  92. package/lib/db/migrations/0003_boring_wild_pack.sql +0 -13
  93. package/lib/db/migrations/0004_windy_tyrannus.sql +0 -27
  94. package/lib/db/migrations/0005_perpetual_doorman.sql +0 -5
  95. package/lib/db/migrations/0006_aberrant_captain_midlands.sql +0 -13
  96. package/lib/db/migrations/0007_clever_captain_cross.sql +0 -14
  97. package/lib/db/migrations/0008_sparkling_pandemic.sql +0 -2
  98. package/lib/db/migrations/0009_happy_black_tom.sql +0 -29
  99. package/lib/db/migrations/0010_kind_junta.sql +0 -8
  100. package/lib/db/migrations/0011_mute_squadron_supreme.sql +0 -25
  101. package/lib/db/migrations/0012_giant_power_man.sql +0 -24
  102. package/lib/db/migrations/0013_damp_titanium_man.sql +0 -17
  103. package/lib/db/migrations/0014_blue_alice.sql +0 -18
  104. package/lib/db/migrations/0015_webhook_tables.sql +0 -41
  105. package/lib/db/migrations/0016_github_integration.sql +0 -30
  106. package/lib/db/migrations/0016_overjoyed_ghost_rider.sql +0 -22
  107. package/lib/db/migrations/0017_slimy_inhumans.sql +0 -6
  108. package/lib/db/migrations/0018_same_spitfire.sql +0 -1
  109. package/lib/db/migrations/0019_jittery_loners.sql +0 -16
  110. package/lib/db/migrations/0019_remove_projects_add_org_settings.sql +0 -14
  111. package/lib/db/migrations/meta/0001_snapshot.json +0 -553
  112. package/lib/db/migrations/meta/0002_snapshot.json +0 -560
  113. package/lib/db/migrations/meta/0003_snapshot.json +0 -650
  114. package/lib/db/migrations/meta/0004_snapshot.json +0 -852
  115. package/lib/db/migrations/meta/0005_snapshot.json +0 -900
  116. package/lib/db/migrations/meta/0006_snapshot.json +0 -1011
  117. package/lib/db/migrations/meta/0007_snapshot.json +0 -1125
  118. package/lib/db/migrations/meta/0008_snapshot.json +0 -1146
  119. package/lib/db/migrations/meta/0009_snapshot.json +0 -1386
  120. package/lib/db/migrations/meta/0010_snapshot.json +0 -1419
  121. package/lib/db/migrations/meta/0011_snapshot.json +0 -1615
  122. package/lib/db/migrations/meta/0012_snapshot.json +0 -1805
  123. package/lib/db/migrations/meta/0013_snapshot.json +0 -1948
  124. package/lib/db/migrations/meta/0014_snapshot.json +0 -2082
  125. package/lib/db/migrations/meta/0015_snapshot.json +0 -2476
  126. package/lib/db/migrations/meta/0016_snapshot.json +0 -2633
  127. package/lib/db/migrations/meta/0017_snapshot.json +0 -2680
  128. package/lib/db/migrations/meta/0018_snapshot.json +0 -2686
  129. package/lib/db/migrations/meta/0019_snapshot.json +0 -2741
  130. package/lib/db/schema/projects.ts +0 -145
  131. package/lib/db/schema/user-profiles.ts +0 -31
  132. package/lib/validations/projects.ts +0 -49
  133. package/next-env.d.ts +0 -6
  134. package/playwright.config.ts +0 -44
  135. package/proxy.test.ts +0 -131
  136. package/proxy.ts +0 -190
  137. package/scripts/backup-db.sh +0 -57
  138. package/scripts/backup-db.ts +0 -24
  139. package/scripts/generate-openapi.ts +0 -22
  140. package/scripts/migration-helper.ts +0 -39
  141. package/scripts/pre-deploy.ts +0 -75
  142. package/scripts/restore-db.sh +0 -60
  143. package/scripts/rollback.ts +0 -72
  144. package/scripts/seed-tags.ts +0 -48
  145. package/tests/api/feedback-bulk.test.ts +0 -47
  146. package/tests/api/feedback-by-id.test.ts +0 -67
  147. package/tests/api/feedback-comments-route-import.test.ts +0 -26
  148. package/tests/api/feedback-create.test.ts +0 -71
  149. package/tests/api/feedback-delete.test.ts +0 -160
  150. package/tests/api/feedback-filter.test.ts +0 -250
  151. package/tests/api/feedback-list.test.ts +0 -234
  152. package/tests/api/feedback-route-assignee-condition.test.ts +0 -32
  153. package/tests/api/feedback-similar.test.ts +0 -46
  154. package/tests/api/feedback-sort.test.ts +0 -261
  155. package/tests/api/feedback-status-enum.test.ts +0 -49
  156. package/tests/api/feedback-status-filter.test.ts +0 -117
  157. package/tests/api/feedback-submit-on-behalf.test.ts +0 -269
  158. package/tests/api/feedback.test.ts +0 -175
  159. package/tests/api/identify-jwt.test.ts +0 -25
  160. package/tests/api/invitation-accept.test.ts +0 -213
  161. package/tests/api/organization-invitations.test.ts +0 -186
  162. package/tests/api/organization-members-list.test.ts +0 -79
  163. package/tests/api/organization-members.test.ts +0 -340
  164. package/tests/api/organizations.test.ts +0 -149
  165. package/tests/api/register.test.ts +0 -112
  166. package/tests/api/upload.test.ts +0 -103
  167. package/tests/api/vote.test.ts +0 -82
  168. package/tests/app/admin-feedback-detail-page.test.tsx +0 -25
  169. package/tests/app/admin-feedback-list-page.test.tsx +0 -25
  170. package/tests/app/admin-feedback-new-page.test.tsx +0 -25
  171. package/tests/app/health-route-helpers.test.ts +0 -27
  172. package/tests/app/login-page.test.ts +0 -26
  173. package/tests/app/portal-page.test.ts +0 -29
  174. package/tests/app/project-portal-overview.test.tsx +0 -25
  175. package/tests/app/widget-page-import.test.ts +0 -25
  176. package/tests/components/create-post-dialog-defaults.test.ts +0 -43
  177. package/tests/components/feedback/duplicate-suggestions-inline.test.tsx +0 -27
  178. package/tests/components/feedback/embedded-feedback-form.test.tsx +0 -96
  179. package/tests/components/feedback/feedback-detail.test.tsx +0 -25
  180. package/tests/components/feedback/feedback-stats.test.tsx +0 -49
  181. package/tests/components/feedback-bulk-actions.test.tsx +0 -39
  182. package/tests/components/feedback-i18n-keys.test.ts +0 -70
  183. package/tests/components/feedback-list-controls-compile.test.ts +0 -25
  184. package/tests/components/feedback-list-controls.test.tsx +0 -204
  185. package/tests/components/feedback-list-item.test.tsx +0 -67
  186. package/tests/components/landing/hero.test.tsx +0 -46
  187. package/tests/components/layout/language-switcher.test.tsx +0 -25
  188. package/tests/components/layout/sidebar.test.tsx +0 -157
  189. package/tests/components/login-form.test.ts +0 -25
  190. package/tests/components/organization-form.test.ts +0 -32
  191. package/tests/components/organization-switcher.test.ts +0 -25
  192. package/tests/components/pagination.test.tsx +0 -43
  193. package/tests/components/portal-overview.test.tsx +0 -25
  194. package/tests/components/profile-form.test.tsx +0 -139
  195. package/tests/components/role-selector.test.ts +0 -31
  196. package/tests/components/status-chart.test.tsx +0 -90
  197. package/tests/e2e/auth.e2e.ts +0 -323
  198. package/tests/e2e/feedback-actions.e2e.ts +0 -471
  199. package/tests/e2e/feedback-attachment.e2e.ts +0 -168
  200. package/tests/e2e/feedback-customer.e2e.ts +0 -226
  201. package/tests/e2e/feedback-management.e2e.ts +0 -565
  202. package/tests/e2e/feedback-submit.e2e.ts +0 -133
  203. package/tests/e2e/feedback-view.e2e.ts +0 -297
  204. package/tests/e2e/fixtures/test-data.ts +0 -235
  205. package/tests/e2e/health-check.e2e.ts +0 -230
  206. package/tests/e2e/helpers/test-utils-helpers.test.ts +0 -43
  207. package/tests/e2e/helpers/test-utils.ts +0 -298
  208. package/tests/e2e/integration-placeholders.e2e.ts +0 -199
  209. package/tests/e2e/organization.e2e.ts +0 -292
  210. package/tests/e2e/permissions.e2e.ts +0 -424
  211. package/tests/e2e/project-widget.e2e.ts +0 -63
  212. package/tests/feedback/filters.test.ts +0 -29
  213. package/tests/hooks/use-permissions.test.ts +0 -52
  214. package/tests/lib/ai/classifier.test.ts +0 -104
  215. package/tests/lib/ai/duplicate-detector.test.ts +0 -234
  216. package/tests/lib/attachments-schema.test.ts +0 -30
  217. package/tests/lib/auth/session.test.ts +0 -49
  218. package/tests/lib/auth-client.test.ts +0 -37
  219. package/tests/lib/auth-config.test.ts +0 -26
  220. package/tests/lib/feedback-prefill.test.ts +0 -52
  221. package/tests/lib/feedback-processor.test.ts +0 -41
  222. package/tests/lib/feedback-schema.test.ts +0 -33
  223. package/tests/lib/file-validator.test.ts +0 -48
  224. package/tests/lib/get-feedback-by-id.test.ts +0 -37
  225. package/tests/lib/invitations.test.ts +0 -35
  226. package/tests/lib/login-schema.test.ts +0 -36
  227. package/tests/lib/org-context.test.ts +0 -95
  228. package/tests/lib/organization-access.test.ts +0 -44
  229. package/tests/lib/organization-member-role-schema.test.ts +0 -41
  230. package/tests/lib/permissions.test.ts +0 -88
  231. package/tests/lib/portal-analytics.test.ts +0 -25
  232. package/tests/lib/portal-contributors.test.ts +0 -25
  233. package/tests/lib/portal-copy.test.ts +0 -27
  234. package/tests/lib/portal-i18n.test.ts +0 -30
  235. package/tests/lib/portal-leaderboard-settings.test.ts +0 -25
  236. package/tests/lib/portal-modules.test.ts +0 -25
  237. package/tests/lib/portal-seo.test.ts +0 -25
  238. package/tests/lib/portal-sharing.test.ts +0 -25
  239. package/tests/lib/portal-sorting.test.ts +0 -25
  240. package/tests/lib/portal-theme.test.ts +0 -25
  241. package/tests/lib/rate-limit.test.ts +0 -142
  242. package/tests/lib/resolve-locale.test.ts +0 -34
  243. package/tests/lib/services/backup.test.ts +0 -145
  244. package/tests/lib/user-organizations.test.ts +0 -42
  245. package/tests/lib/user-role-schema.test.ts +0 -33
  246. package/tests/lib/user-schema.test.ts +0 -25
  247. package/tests/setup.ts +0 -74
  248. package/vercel.json +0 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @nexttylabs/echo
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5cfdeb7: feat: support editing user profile
8
+
9
+ ### Patch Changes
10
+
11
+ - 7dba561: remove legacy changeset files
12
+ - 1e798f1: remove unuse tables and published files
13
+ - e3c4e1c: fix workflow errors
14
+ - daf9abb: first release
15
+
16
+ ## 0.4.0
17
+
18
+ ### Minor Changes
19
+
20
+ - 5cfdeb7: feat: support editing user profile
21
+
22
+ ### Patch Changes
23
+
24
+ - 7dba561: remove legacy changeset files
25
+ - e3c4e1c: fix workflow errors
26
+ - daf9abb: first release
27
+
3
28
  ## 0.3.0
4
29
 
5
30
  ### Minor Changes
@@ -19,6 +19,7 @@ import Link from "next/link";
19
19
  import { notFound } from "next/navigation";
20
20
  import { and, desc, eq, isNull, sql } from "drizzle-orm";
21
21
  import { headers } from "next/headers";
22
+ import { organizationMembers } from "@/lib/db/schema";
22
23
  import { auth } from "@/lib/auth/config";
23
24
  import { PortalLayout } from "@/components/portal/portal-layout";
24
25
  import { RoadmapBoard, type RoadmapStatus } from "@/components/portal/roadmap-board";
@@ -108,7 +109,24 @@ export default async function OrganizationRoadmapPage({ params }: PageProps) {
108
109
 
109
110
  // Check if user is admin
110
111
  const session = await auth.api.getSession({ headers: await headers() });
111
- const isAdmin = session?.user?.role === "admin" || session?.user?.role === "owner";
112
+ let isAdmin = false;
113
+
114
+ if (session?.user?.id) {
115
+ const { db } = await import("@/lib/db");
116
+ if (db) {
117
+ const [member] = await db
118
+ .select({ role: organizationMembers.role })
119
+ .from(organizationMembers)
120
+ .where(
121
+ and(
122
+ eq(organizationMembers.organizationId, organization.id),
123
+ eq(organizationMembers.userId, session.user.id)
124
+ )
125
+ )
126
+ .limit(1);
127
+ isAdmin = member?.role === "admin" || member?.role === "owner";
128
+ }
129
+ }
112
130
 
113
131
  const items = await getRoadmapItems(organization.id);
114
132
  const sections = getPortalSections(organizationSlug, context.modules);
@@ -24,6 +24,8 @@ import {
24
24
  getBackupConfig,
25
25
  } from "@/lib/services/backup";
26
26
  import { apiError } from "@/lib/api/errors";
27
+ import { db } from "@/lib/db";
28
+ import { getUserOrganizations } from "@/lib/auth/organization";
27
29
 
28
30
  export async function POST(req: NextRequest) {
29
31
  try {
@@ -32,8 +34,16 @@ export async function POST(req: NextRequest) {
32
34
  return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
33
35
  }
34
36
 
35
- const role = (session.user as { role: UserRole }).role;
36
- if (!role || !hasPermission(role, PERMISSIONS.BACKUP_CREATE)) {
37
+ if (!db) {
38
+ return NextResponse.json({ error: "Database not available" }, { status: 503 });
39
+ }
40
+
41
+ const orgs = await getUserOrganizations(db, session.user.id);
42
+ const hasAccess = orgs.some(org =>
43
+ hasPermission(org.role as UserRole, PERMISSIONS.BACKUP_CREATE)
44
+ );
45
+
46
+ if (!hasAccess) {
37
47
  return NextResponse.json({ error: "Forbidden" }, { status: 403 });
38
48
  }
39
49
 
@@ -57,8 +67,16 @@ export async function GET(req: NextRequest) {
57
67
  return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
58
68
  }
59
69
 
60
- const role = (session.user as { role: UserRole }).role;
61
- if (!role || !hasPermission(role, PERMISSIONS.BACKUP_VIEW)) {
70
+ if (!db) {
71
+ return NextResponse.json({ error: "Database not available" }, { status: 503 });
72
+ }
73
+
74
+ const orgs = await getUserOrganizations(db, session.user.id);
75
+ const hasAccess = orgs.some(org =>
76
+ hasPermission(org.role as UserRole, PERMISSIONS.BACKUP_VIEW)
77
+ );
78
+
79
+ if (!hasAccess) {
62
80
  return NextResponse.json({ error: "Forbidden" }, { status: 403 });
63
81
  }
64
82
 
@@ -22,7 +22,7 @@ import { APIError } from "better-auth/api";
22
22
  import type { db as database } from "@/lib/db";
23
23
  import { registerSchema } from "@/lib/validations/auth";
24
24
  import { generateSlug } from "@/lib/utils/slug";
25
- import { user, organizations, organizationMembers, userProfiles } from "@/lib/db/schema";
25
+ import { user, organizations, organizationMembers } from "@/lib/db/schema";
26
26
  import { logger } from "@/lib/logger";
27
27
 
28
28
  type Database = NonNullable<typeof database>;
@@ -98,7 +98,6 @@ export function buildRegisterHandler(deps: RegisterDeps) {
98
98
 
99
99
  try {
100
100
  await deps.db.transaction(async (tx) => {
101
- await tx.insert(userProfiles).values({ userId, name });
102
101
  await tx
103
102
  .insert(organizations)
104
103
  .values({ id: organizationId, name: orgName, slug: orgSlug });
@@ -38,13 +38,6 @@ export const auth = betterAuth({
38
38
  provider: "pg",
39
39
  schema,
40
40
  }),
41
- user: {
42
- additionalFields: {
43
- role: {
44
- type: "string",
45
- },
46
- },
47
- },
48
41
  emailAndPassword: {
49
42
  enabled: true,
50
43
  },
@@ -0,0 +1,335 @@
1
+ CREATE TABLE "ai_processing_results" (
2
+ "id" serial PRIMARY KEY NOT NULL,
3
+ "feedbackId" integer NOT NULL,
4
+ "classification" jsonb,
5
+ "tagSuggestions" jsonb,
6
+ "duplicateCandidates" jsonb,
7
+ "processingTime" integer,
8
+ "status" text DEFAULT 'pending' NOT NULL,
9
+ "errorMessage" text,
10
+ "createdAt" timestamp DEFAULT now() NOT NULL,
11
+ "updatedAt" timestamp DEFAULT now() NOT NULL
12
+ );
13
+ --> statement-breakpoint
14
+ CREATE TABLE "api_keys" (
15
+ "keyId" serial PRIMARY KEY NOT NULL,
16
+ "name" text NOT NULL,
17
+ "hashedKey" text NOT NULL,
18
+ "prefix" text NOT NULL,
19
+ "organizationId" text NOT NULL,
20
+ "disabled" boolean DEFAULT false NOT NULL,
21
+ "lastUsed" timestamp,
22
+ "createdAt" timestamp DEFAULT now() NOT NULL,
23
+ "updatedAt" timestamp DEFAULT now() NOT NULL,
24
+ CONSTRAINT "api_keys_hashedKey_unique" UNIQUE("hashedKey")
25
+ );
26
+ --> statement-breakpoint
27
+ CREATE TABLE "attachments" (
28
+ "attachmentId" serial PRIMARY KEY NOT NULL,
29
+ "feedbackId" integer NOT NULL,
30
+ "fileName" text NOT NULL,
31
+ "filePath" text NOT NULL,
32
+ "fileSize" integer NOT NULL,
33
+ "mimeType" text NOT NULL,
34
+ "createdAt" timestamp DEFAULT now() NOT NULL
35
+ );
36
+ --> statement-breakpoint
37
+ CREATE TABLE "account" (
38
+ "id" text PRIMARY KEY NOT NULL,
39
+ "account_id" text NOT NULL,
40
+ "provider_id" text NOT NULL,
41
+ "user_id" text NOT NULL,
42
+ "access_token" text,
43
+ "refresh_token" text,
44
+ "id_token" text,
45
+ "access_token_expires_at" timestamp,
46
+ "refresh_token_expires_at" timestamp,
47
+ "scope" text,
48
+ "password" text,
49
+ "created_at" timestamp DEFAULT now() NOT NULL,
50
+ "updated_at" timestamp NOT NULL
51
+ );
52
+ --> statement-breakpoint
53
+ CREATE TABLE "session" (
54
+ "id" text PRIMARY KEY NOT NULL,
55
+ "expires_at" timestamp NOT NULL,
56
+ "token" text NOT NULL,
57
+ "created_at" timestamp DEFAULT now() NOT NULL,
58
+ "updated_at" timestamp NOT NULL,
59
+ "ip_address" text,
60
+ "user_agent" text,
61
+ "user_id" text NOT NULL,
62
+ CONSTRAINT "session_token_unique" UNIQUE("token")
63
+ );
64
+ --> statement-breakpoint
65
+ CREATE TABLE "user" (
66
+ "id" text PRIMARY KEY NOT NULL,
67
+ "name" text NOT NULL,
68
+ "email" text NOT NULL,
69
+ "email_verified" boolean DEFAULT false NOT NULL,
70
+ "image" text,
71
+ "created_at" timestamp DEFAULT now() NOT NULL,
72
+ "updated_at" timestamp DEFAULT now() NOT NULL,
73
+ CONSTRAINT "user_email_unique" UNIQUE("email")
74
+ );
75
+ --> statement-breakpoint
76
+ CREATE TABLE "verification" (
77
+ "id" text PRIMARY KEY NOT NULL,
78
+ "identifier" text NOT NULL,
79
+ "value" text NOT NULL,
80
+ "expires_at" timestamp NOT NULL,
81
+ "created_at" timestamp DEFAULT now() NOT NULL,
82
+ "updated_at" timestamp DEFAULT now() NOT NULL
83
+ );
84
+ --> statement-breakpoint
85
+ CREATE TABLE "comments" (
86
+ "commentId" serial PRIMARY KEY NOT NULL,
87
+ "feedbackId" serial NOT NULL,
88
+ "userId" text,
89
+ "authorName" text,
90
+ "authorEmail" text,
91
+ "guestToken" text,
92
+ "content" text NOT NULL,
93
+ "isInternal" boolean DEFAULT true NOT NULL,
94
+ "createdAt" timestamp DEFAULT now() NOT NULL,
95
+ "updatedAt" timestamp DEFAULT now() NOT NULL
96
+ );
97
+ --> statement-breakpoint
98
+ CREATE TABLE "duplicate_feedback" (
99
+ "id" serial PRIMARY KEY NOT NULL,
100
+ "originalFeedbackId" integer NOT NULL,
101
+ "duplicateFeedbackId" integer NOT NULL,
102
+ "similarity" integer NOT NULL,
103
+ "status" text DEFAULT 'pending' NOT NULL,
104
+ "createdAt" timestamp DEFAULT now() NOT NULL,
105
+ "confirmedBy" text,
106
+ "confirmedAt" timestamp,
107
+ CONSTRAINT "unique_duplicate_pair" UNIQUE("originalFeedbackId","duplicateFeedbackId")
108
+ );
109
+ --> statement-breakpoint
110
+ CREATE TABLE "feedback" (
111
+ "feedbackId" serial PRIMARY KEY NOT NULL,
112
+ "title" text NOT NULL,
113
+ "description" text NOT NULL,
114
+ "type" text NOT NULL,
115
+ "priority" text NOT NULL,
116
+ "status" text DEFAULT 'new' NOT NULL,
117
+ "organizationId" text NOT NULL,
118
+ "submittedOnBehalf" boolean DEFAULT false NOT NULL,
119
+ "submittedBy" text,
120
+ "customerInfo" jsonb,
121
+ "createdAt" timestamp DEFAULT now() NOT NULL,
122
+ "updatedAt" timestamp DEFAULT now() NOT NULL,
123
+ "deletedAt" timestamp,
124
+ "autoClassified" boolean DEFAULT false NOT NULL,
125
+ "processingStatus" text DEFAULT 'pending',
126
+ "processedAt" timestamp,
127
+ "githubIssueId" integer,
128
+ "githubIssueNumber" integer,
129
+ "githubIssueUrl" text,
130
+ "githubSyncedAt" timestamp,
131
+ "githubStatus" text
132
+ );
133
+ --> statement-breakpoint
134
+ CREATE TABLE "github_integrations" (
135
+ "id" serial PRIMARY KEY NOT NULL,
136
+ "organizationId" text NOT NULL,
137
+ "accessToken" text NOT NULL,
138
+ "owner" text NOT NULL,
139
+ "repo" text NOT NULL,
140
+ "labelMapping" jsonb,
141
+ "statusMapping" jsonb,
142
+ "autoSync" boolean DEFAULT true NOT NULL,
143
+ "webhookSecret" text,
144
+ "createdAt" timestamp DEFAULT now() NOT NULL,
145
+ "updatedAt" timestamp DEFAULT now() NOT NULL
146
+ );
147
+ --> statement-breakpoint
148
+ CREATE TABLE "organizations" (
149
+ "id" text PRIMARY KEY NOT NULL,
150
+ "name" text NOT NULL,
151
+ "slug" text NOT NULL,
152
+ "description" text,
153
+ "created_at" timestamp DEFAULT now() NOT NULL,
154
+ "updated_at" timestamp DEFAULT now() NOT NULL,
155
+ CONSTRAINT "organizations_slug_unique" UNIQUE("slug")
156
+ );
157
+ --> statement-breakpoint
158
+ CREATE TABLE "organization_settings" (
159
+ "organizationId" text PRIMARY KEY NOT NULL,
160
+ "widgetConfig" jsonb,
161
+ "portalConfig" jsonb,
162
+ "customDomain" text,
163
+ "createdAt" timestamp DEFAULT now() NOT NULL,
164
+ "updatedAt" timestamp DEFAULT now() NOT NULL,
165
+ CONSTRAINT "unique_org_custom_domain" UNIQUE("customDomain")
166
+ );
167
+ --> statement-breakpoint
168
+ CREATE TABLE "organization_members" (
169
+ "organization_id" text NOT NULL,
170
+ "user_id" text NOT NULL,
171
+ "role" text NOT NULL,
172
+ "created_at" timestamp DEFAULT now() NOT NULL,
173
+ CONSTRAINT "organization_members_organization_id_user_id_pk" PRIMARY KEY("organization_id","user_id")
174
+ );
175
+ --> statement-breakpoint
176
+ CREATE TABLE "invitations" (
177
+ "id" text PRIMARY KEY NOT NULL,
178
+ "organization_id" text NOT NULL,
179
+ "email" text NOT NULL,
180
+ "role" text NOT NULL,
181
+ "token" text NOT NULL,
182
+ "expires_at" timestamp NOT NULL,
183
+ "accepted_at" timestamp,
184
+ "created_at" timestamp DEFAULT now() NOT NULL,
185
+ CONSTRAINT "invitations_token_unique" UNIQUE("token")
186
+ );
187
+ --> statement-breakpoint
188
+ CREATE TABLE "votes" (
189
+ "voteId" serial PRIMARY KEY NOT NULL,
190
+ "feedbackId" serial NOT NULL,
191
+ "visitorId" text,
192
+ "userId" text,
193
+ "createdAt" timestamp DEFAULT now() NOT NULL,
194
+ CONSTRAINT "unique_vote" UNIQUE("feedbackId","visitorId")
195
+ );
196
+ --> statement-breakpoint
197
+ CREATE TABLE "status_history" (
198
+ "historyId" serial PRIMARY KEY NOT NULL,
199
+ "feedbackId" integer NOT NULL,
200
+ "oldStatus" text NOT NULL,
201
+ "newStatus" text NOT NULL,
202
+ "changedBy" text,
203
+ "changedAt" timestamp DEFAULT now() NOT NULL,
204
+ "comment" text
205
+ );
206
+ --> statement-breakpoint
207
+ CREATE TABLE "notification_preferences" (
208
+ "userId" text PRIMARY KEY NOT NULL,
209
+ "statusChange" boolean DEFAULT true NOT NULL,
210
+ "newComment" boolean DEFAULT true NOT NULL,
211
+ "updatedAt" timestamp DEFAULT now() NOT NULL
212
+ );
213
+ --> statement-breakpoint
214
+ CREATE TABLE "notifications" (
215
+ "notificationId" serial PRIMARY KEY NOT NULL,
216
+ "userId" text NOT NULL,
217
+ "type" text NOT NULL,
218
+ "feedbackId" serial NOT NULL,
219
+ "data" jsonb,
220
+ "status" text DEFAULT 'pending' NOT NULL,
221
+ "sentAt" timestamp,
222
+ "error" text,
223
+ "createdAt" timestamp DEFAULT now() NOT NULL
224
+ );
225
+ --> statement-breakpoint
226
+ CREATE TABLE "feedback_tags" (
227
+ "id" serial PRIMARY KEY NOT NULL,
228
+ "feedbackId" integer NOT NULL,
229
+ "tagId" integer NOT NULL,
230
+ "createdAt" timestamp DEFAULT now() NOT NULL
231
+ );
232
+ --> statement-breakpoint
233
+ CREATE TABLE "tags" (
234
+ "tagId" serial PRIMARY KEY NOT NULL,
235
+ "name" text NOT NULL,
236
+ "slug" text NOT NULL,
237
+ "color" text DEFAULT '#3b82f6',
238
+ "description" text,
239
+ "createdAt" timestamp DEFAULT now() NOT NULL,
240
+ CONSTRAINT "tags_name_unique" UNIQUE("name"),
241
+ CONSTRAINT "tags_slug_unique" UNIQUE("slug")
242
+ );
243
+ --> statement-breakpoint
244
+ CREATE TABLE "webhook_events" (
245
+ "eventId" serial PRIMARY KEY NOT NULL,
246
+ "webhookId" integer NOT NULL,
247
+ "eventType" text NOT NULL,
248
+ "payload" jsonb NOT NULL,
249
+ "status" text DEFAULT 'pending' NOT NULL,
250
+ "responseStatus" integer,
251
+ "responseBody" text,
252
+ "retryCount" integer DEFAULT 0 NOT NULL,
253
+ "maxRetries" integer DEFAULT 3 NOT NULL,
254
+ "nextRetryAt" timestamp,
255
+ "deliveredAt" timestamp,
256
+ "createdAt" timestamp DEFAULT now() NOT NULL,
257
+ "updatedAt" timestamp DEFAULT now() NOT NULL
258
+ );
259
+ --> statement-breakpoint
260
+ CREATE TABLE "webhooks" (
261
+ "webhookId" serial PRIMARY KEY NOT NULL,
262
+ "organizationId" text NOT NULL,
263
+ "name" text NOT NULL,
264
+ "url" text NOT NULL,
265
+ "secret" text,
266
+ "events" jsonb NOT NULL,
267
+ "enabled" boolean DEFAULT true NOT NULL,
268
+ "createdAt" timestamp DEFAULT now() NOT NULL,
269
+ "updatedAt" timestamp DEFAULT now() NOT NULL
270
+ );
271
+ --> statement-breakpoint
272
+ ALTER TABLE "ai_processing_results" ADD CONSTRAINT "ai_processing_results_feedbackId_feedback_feedbackId_fk" FOREIGN KEY ("feedbackId") REFERENCES "public"."feedback"("feedbackId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
273
+ ALTER TABLE "api_keys" ADD CONSTRAINT "api_keys_organizationId_organizations_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
274
+ ALTER TABLE "attachments" ADD CONSTRAINT "attachments_feedbackId_feedback_feedbackId_fk" FOREIGN KEY ("feedbackId") REFERENCES "public"."feedback"("feedbackId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
275
+ ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
276
+ ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
277
+ ALTER TABLE "comments" ADD CONSTRAINT "comments_feedbackId_feedback_feedbackId_fk" FOREIGN KEY ("feedbackId") REFERENCES "public"."feedback"("feedbackId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
278
+ ALTER TABLE "comments" ADD CONSTRAINT "comments_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
279
+ ALTER TABLE "duplicate_feedback" ADD CONSTRAINT "duplicate_feedback_originalFeedbackId_feedback_feedbackId_fk" FOREIGN KEY ("originalFeedbackId") REFERENCES "public"."feedback"("feedbackId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
280
+ ALTER TABLE "duplicate_feedback" ADD CONSTRAINT "duplicate_feedback_duplicateFeedbackId_feedback_feedbackId_fk" FOREIGN KEY ("duplicateFeedbackId") REFERENCES "public"."feedback"("feedbackId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
281
+ ALTER TABLE "duplicate_feedback" ADD CONSTRAINT "duplicate_feedback_confirmedBy_user_id_fk" FOREIGN KEY ("confirmedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
282
+ ALTER TABLE "feedback" ADD CONSTRAINT "feedback_submittedBy_user_id_fk" FOREIGN KEY ("submittedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
283
+ ALTER TABLE "github_integrations" ADD CONSTRAINT "github_integrations_organizationId_organizations_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
284
+ ALTER TABLE "organization_settings" ADD CONSTRAINT "organization_settings_organizationId_organizations_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
285
+ ALTER TABLE "organization_members" ADD CONSTRAINT "organization_members_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
286
+ ALTER TABLE "organization_members" ADD CONSTRAINT "organization_members_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
287
+ ALTER TABLE "invitations" ADD CONSTRAINT "invitations_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
288
+ ALTER TABLE "votes" ADD CONSTRAINT "votes_feedbackId_feedback_feedbackId_fk" FOREIGN KEY ("feedbackId") REFERENCES "public"."feedback"("feedbackId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
289
+ ALTER TABLE "votes" ADD CONSTRAINT "votes_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
290
+ ALTER TABLE "status_history" ADD CONSTRAINT "status_history_feedbackId_feedback_feedbackId_fk" FOREIGN KEY ("feedbackId") REFERENCES "public"."feedback"("feedbackId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
291
+ ALTER TABLE "status_history" ADD CONSTRAINT "status_history_changedBy_user_id_fk" FOREIGN KEY ("changedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
292
+ ALTER TABLE "notification_preferences" ADD CONSTRAINT "notification_preferences_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
293
+ ALTER TABLE "notifications" ADD CONSTRAINT "notifications_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
294
+ ALTER TABLE "notifications" ADD CONSTRAINT "notifications_feedbackId_feedback_feedbackId_fk" FOREIGN KEY ("feedbackId") REFERENCES "public"."feedback"("feedbackId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
295
+ ALTER TABLE "feedback_tags" ADD CONSTRAINT "feedback_tags_feedbackId_feedback_feedbackId_fk" FOREIGN KEY ("feedbackId") REFERENCES "public"."feedback"("feedbackId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
296
+ ALTER TABLE "feedback_tags" ADD CONSTRAINT "feedback_tags_tagId_tags_tagId_fk" FOREIGN KEY ("tagId") REFERENCES "public"."tags"("tagId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
297
+ ALTER TABLE "webhook_events" ADD CONSTRAINT "webhook_events_webhookId_webhooks_webhookId_fk" FOREIGN KEY ("webhookId") REFERENCES "public"."webhooks"("webhookId") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
298
+ ALTER TABLE "webhooks" ADD CONSTRAINT "webhooks_organizationId_organizations_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
299
+ CREATE INDEX "idx_ai_results_feedback" ON "ai_processing_results" USING btree ("feedbackId");--> statement-breakpoint
300
+ CREATE INDEX "idx_ai_results_status" ON "ai_processing_results" USING btree ("status");--> statement-breakpoint
301
+ CREATE INDEX "idx_api_keys_hashedKey" ON "api_keys" USING btree ("hashedKey");--> statement-breakpoint
302
+ CREATE INDEX "idx_api_keys_orgId" ON "api_keys" USING btree ("organizationId");--> statement-breakpoint
303
+ CREATE INDEX "idx_attachments_feedbackId" ON "attachments" USING btree ("feedbackId");--> statement-breakpoint
304
+ CREATE INDEX "account_userId_idx" ON "account" USING btree ("user_id");--> statement-breakpoint
305
+ CREATE INDEX "session_userId_idx" ON "session" USING btree ("user_id");--> statement-breakpoint
306
+ CREATE INDEX "verification_identifier_idx" ON "verification" USING btree ("identifier");--> statement-breakpoint
307
+ CREATE INDEX "idx_comments_feedbackId" ON "comments" USING btree ("feedbackId");--> statement-breakpoint
308
+ CREATE INDEX "idx_comments_isInternal" ON "comments" USING btree ("isInternal");--> statement-breakpoint
309
+ CREATE INDEX "idx_comments_internal_feedbacks" ON "comments" USING btree ("feedbackId","isInternal");--> statement-breakpoint
310
+ CREATE INDEX "idx_comments_guestToken" ON "comments" USING btree ("guestToken");--> statement-breakpoint
311
+ CREATE INDEX "idx_duplicate_original" ON "duplicate_feedback" USING btree ("originalFeedbackId");--> statement-breakpoint
312
+ CREATE INDEX "idx_duplicate_duplicate" ON "duplicate_feedback" USING btree ("duplicateFeedbackId");--> statement-breakpoint
313
+ CREATE INDEX "idx_feedback_orgId" ON "feedback" USING btree ("organizationId");--> statement-breakpoint
314
+ CREATE INDEX "idx_feedback_status" ON "feedback" USING btree ("status");--> statement-breakpoint
315
+ CREATE INDEX "idx_feedback_createdAt" ON "feedback" USING btree ("createdAt");--> statement-breakpoint
316
+ CREATE INDEX "idx_feedback_submittedBy" ON "feedback" USING btree ("submittedBy");--> statement-breakpoint
317
+ CREATE INDEX "idx_feedback_deletedAt" ON "feedback" USING btree ("deletedAt");--> statement-breakpoint
318
+ CREATE INDEX "idx_feedback_githubIssueId" ON "feedback" USING btree ("githubIssueId");--> statement-breakpoint
319
+ CREATE INDEX "idx_github_integrations_orgId" ON "github_integrations" USING btree ("organizationId");--> statement-breakpoint
320
+ CREATE INDEX "idx_org_settings_orgId" ON "organization_settings" USING btree ("organizationId");--> statement-breakpoint
321
+ CREATE INDEX "idx_votes_feedbackId" ON "votes" USING btree ("feedbackId");--> statement-breakpoint
322
+ CREATE INDEX "idx_votes_userId" ON "votes" USING btree ("userId");--> statement-breakpoint
323
+ CREATE INDEX "idx_status_history_feedbackId" ON "status_history" USING btree ("feedbackId");--> statement-breakpoint
324
+ CREATE INDEX "idx_status_history_changedAt" ON "status_history" USING btree ("changedAt");--> statement-breakpoint
325
+ CREATE INDEX "idx_notifications_userId" ON "notifications" USING btree ("userId");--> statement-breakpoint
326
+ CREATE INDEX "idx_notifications_status" ON "notifications" USING btree ("status");--> statement-breakpoint
327
+ CREATE INDEX "idx_notifications_type" ON "notifications" USING btree ("type");--> statement-breakpoint
328
+ CREATE INDEX "idx_feedback_tags_feedbackId" ON "feedback_tags" USING btree ("feedbackId");--> statement-breakpoint
329
+ CREATE INDEX "idx_feedback_tags_tagId" ON "feedback_tags" USING btree ("tagId");--> statement-breakpoint
330
+ CREATE INDEX "idx_feedback_tags_unique" ON "feedback_tags" USING btree ("feedbackId","tagId");--> statement-breakpoint
331
+ CREATE INDEX "idx_webhook_events_webhookId" ON "webhook_events" USING btree ("webhookId");--> statement-breakpoint
332
+ CREATE INDEX "idx_webhook_events_status" ON "webhook_events" USING btree ("status");--> statement-breakpoint
333
+ CREATE INDEX "idx_webhook_events_nextRetry" ON "webhook_events" USING btree ("nextRetryAt");--> statement-breakpoint
334
+ CREATE INDEX "idx_webhooks_orgId" ON "webhooks" USING btree ("organizationId");--> statement-breakpoint
335
+ CREATE INDEX "idx_webhooks_enabled" ON "webhooks" USING btree ("enabled");