@nexttylabs/echo 0.4.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 (247) hide show
  1. package/CHANGELOG.md +13 -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/bun.lock +0 -2503
  27. package/components/portal/project-switcher.tsx +0 -20
  28. package/docker-compose.dev.yml +0 -26
  29. package/docker-compose.yml +0 -98
  30. package/docs/architecture.md +0 -259
  31. package/docs/component-inventory.md +0 -261
  32. package/docs/database-migrations.md +0 -76
  33. package/docs/development-guide.md +0 -209
  34. package/docs/e2e-user-flows.csv +0 -31
  35. package/docs/er-diagram-feedback.mmd +0 -138
  36. package/docs/er-diagram.mmd +0 -281
  37. package/docs/i18n-check-report.md +0 -296
  38. package/docs/index.md +0 -214
  39. package/docs/logic-chain.md +0 -94
  40. package/docs/plans/2026-01-02-database-migration-scripts.md +0 -496
  41. package/docs/plans/2026-01-02-user-login-design.md +0 -37
  42. package/docs/plans/2026-01-02-user-login.md +0 -437
  43. package/docs/plans/2026-01-02-user-registration-design.md +0 -47
  44. package/docs/plans/2026-01-02-user-registration.md +0 -628
  45. package/docs/plans/2026-01-03-roles-permissions-design.md +0 -20
  46. package/docs/plans/2026-01-03-roles-permissions.md +0 -266
  47. package/docs/plans/2026-01-05-authentication-middleware.md +0 -207
  48. package/docs/plans/2026-01-05-member-removal.md +0 -186
  49. package/docs/plans/2026-01-05-organization-creation.md +0 -374
  50. package/docs/plans/2026-01-05-rbac-middleware.md +0 -112
  51. package/docs/plans/2026-01-05-role-configuration.md +0 -441
  52. package/docs/plans/2026-01-06-file-upload-support.md +0 -804
  53. package/docs/plans/2026-01-06-permission-check-hook.md +0 -155
  54. package/docs/plans/2026-01-06-resource-ownership-check.md +0 -231
  55. package/docs/plans/2026-01-07-feedback-tracking-link.md +0 -459
  56. package/docs/plans/2026-01-09-logout-redirect-design.md +0 -52
  57. package/docs/plans/2026-01-09-phase2-3-plan.md +0 -654
  58. package/docs/plans/2026-01-09-portal-execution-plan.md +0 -408
  59. package/docs/plans/2026-01-09-project-delete-feature-design.md +0 -163
  60. package/docs/plans/2026-01-09-project-delete-implementation.md +0 -451
  61. package/docs/plans/2026-01-09-project-edit-delete-design.md +0 -52
  62. package/docs/plans/2026-01-09-settings-center-design.md +0 -114
  63. package/docs/plans/2026-01-09-settings-center.md +0 -948
  64. package/docs/plans/2026-01-10-organization-only-design.md +0 -66
  65. package/docs/plans/2026-01-10-organization-only-implementation.md +0 -433
  66. package/docs/plans/2026-01-10-portal-settings-restructure-plan.md +0 -18
  67. package/docs/plans/2026-01-10-project-settings-tabs-design-implementation.md +0 -296
  68. package/docs/plans/2026-01-14-e2e-playwright-feedback.md +0 -173
  69. package/docs/plans/2026-01-15-feedback-management-org-context-design.md +0 -82
  70. package/docs/plans/2026-01-15-feedback-management-org-context-implementation-plan.md +0 -521
  71. package/docs/plans/2026-01-16-admin-feedback-filters-design.md +0 -75
  72. package/docs/plans/2026-01-16-admin-feedback-filters-implementation.md +0 -293
  73. package/docs/plans/2026-01-16-admin-feedback-route-consolidation.md +0 -180
  74. package/docs/plans/2026-01-16-e2e-test-fixes.md +0 -158
  75. package/docs/plans/2026-01-17-admin-feedback-filters.md +0 -214
  76. package/docs/plans/2026-01-17-admin-feedback-improvements.md +0 -453
  77. package/docs/plans/2026-01-18-changesets-design.md +0 -40
  78. package/docs/product_changes.md +0 -37
  79. package/docs/project-overview.md +0 -159
  80. package/docs/project-scan-report.json +0 -104
  81. package/docs/route-role-visibility.md +0 -51
  82. package/docs/source-tree-analysis.md +0 -150
  83. package/docs/testing/delete-project-manual-tests.md +0 -18
  84. package/docs/user-story-tracking.md +0 -191
  85. package/eslint.config.mjs +0 -19
  86. package/lib/db/migrations/.gitkeep +0 -0
  87. package/lib/db/migrations/0000_cynical_gladiator.sql +0 -53
  88. package/lib/db/migrations/0001_wandering_sunfire.sql +0 -27
  89. package/lib/db/migrations/0002_shallow_speedball.sql +0 -1
  90. package/lib/db/migrations/0003_add_org_description.sql +0 -1
  91. package/lib/db/migrations/0003_boring_wild_pack.sql +0 -13
  92. package/lib/db/migrations/0004_windy_tyrannus.sql +0 -27
  93. package/lib/db/migrations/0005_perpetual_doorman.sql +0 -5
  94. package/lib/db/migrations/0006_aberrant_captain_midlands.sql +0 -13
  95. package/lib/db/migrations/0007_clever_captain_cross.sql +0 -14
  96. package/lib/db/migrations/0008_sparkling_pandemic.sql +0 -2
  97. package/lib/db/migrations/0009_happy_black_tom.sql +0 -29
  98. package/lib/db/migrations/0010_kind_junta.sql +0 -8
  99. package/lib/db/migrations/0011_mute_squadron_supreme.sql +0 -25
  100. package/lib/db/migrations/0012_giant_power_man.sql +0 -24
  101. package/lib/db/migrations/0013_damp_titanium_man.sql +0 -17
  102. package/lib/db/migrations/0014_blue_alice.sql +0 -18
  103. package/lib/db/migrations/0015_webhook_tables.sql +0 -41
  104. package/lib/db/migrations/0016_github_integration.sql +0 -30
  105. package/lib/db/migrations/0016_overjoyed_ghost_rider.sql +0 -22
  106. package/lib/db/migrations/0017_slimy_inhumans.sql +0 -6
  107. package/lib/db/migrations/0018_same_spitfire.sql +0 -1
  108. package/lib/db/migrations/0019_jittery_loners.sql +0 -16
  109. package/lib/db/migrations/0019_remove_projects_add_org_settings.sql +0 -14
  110. package/lib/db/migrations/meta/0001_snapshot.json +0 -553
  111. package/lib/db/migrations/meta/0002_snapshot.json +0 -560
  112. package/lib/db/migrations/meta/0003_snapshot.json +0 -650
  113. package/lib/db/migrations/meta/0004_snapshot.json +0 -852
  114. package/lib/db/migrations/meta/0005_snapshot.json +0 -900
  115. package/lib/db/migrations/meta/0006_snapshot.json +0 -1011
  116. package/lib/db/migrations/meta/0007_snapshot.json +0 -1125
  117. package/lib/db/migrations/meta/0008_snapshot.json +0 -1146
  118. package/lib/db/migrations/meta/0009_snapshot.json +0 -1386
  119. package/lib/db/migrations/meta/0010_snapshot.json +0 -1419
  120. package/lib/db/migrations/meta/0011_snapshot.json +0 -1615
  121. package/lib/db/migrations/meta/0012_snapshot.json +0 -1805
  122. package/lib/db/migrations/meta/0013_snapshot.json +0 -1948
  123. package/lib/db/migrations/meta/0014_snapshot.json +0 -2082
  124. package/lib/db/migrations/meta/0015_snapshot.json +0 -2476
  125. package/lib/db/migrations/meta/0016_snapshot.json +0 -2633
  126. package/lib/db/migrations/meta/0017_snapshot.json +0 -2680
  127. package/lib/db/migrations/meta/0018_snapshot.json +0 -2686
  128. package/lib/db/migrations/meta/0019_snapshot.json +0 -2741
  129. package/lib/db/schema/projects.ts +0 -145
  130. package/lib/db/schema/user-profiles.ts +0 -31
  131. package/lib/validations/projects.ts +0 -49
  132. package/next-env.d.ts +0 -6
  133. package/playwright.config.ts +0 -44
  134. package/proxy.test.ts +0 -131
  135. package/proxy.ts +0 -116
  136. package/scripts/backup-db.sh +0 -57
  137. package/scripts/backup-db.ts +0 -24
  138. package/scripts/generate-openapi.ts +0 -22
  139. package/scripts/migration-helper.ts +0 -39
  140. package/scripts/pre-deploy.ts +0 -75
  141. package/scripts/restore-db.sh +0 -60
  142. package/scripts/rollback.ts +0 -72
  143. package/scripts/seed-tags.ts +0 -48
  144. package/tests/api/feedback-bulk.test.ts +0 -47
  145. package/tests/api/feedback-by-id.test.ts +0 -67
  146. package/tests/api/feedback-comments-route-import.test.ts +0 -26
  147. package/tests/api/feedback-create.test.ts +0 -71
  148. package/tests/api/feedback-delete.test.ts +0 -160
  149. package/tests/api/feedback-filter.test.ts +0 -250
  150. package/tests/api/feedback-list.test.ts +0 -234
  151. package/tests/api/feedback-route-assignee-condition.test.ts +0 -32
  152. package/tests/api/feedback-similar.test.ts +0 -46
  153. package/tests/api/feedback-sort.test.ts +0 -261
  154. package/tests/api/feedback-status-enum.test.ts +0 -49
  155. package/tests/api/feedback-status-filter.test.ts +0 -117
  156. package/tests/api/feedback-submit-on-behalf.test.ts +0 -269
  157. package/tests/api/feedback.test.ts +0 -175
  158. package/tests/api/identify-jwt.test.ts +0 -25
  159. package/tests/api/invitation-accept.test.ts +0 -213
  160. package/tests/api/organization-invitations.test.ts +0 -186
  161. package/tests/api/organization-members-list.test.ts +0 -79
  162. package/tests/api/organization-members.test.ts +0 -340
  163. package/tests/api/organizations.test.ts +0 -149
  164. package/tests/api/register.test.ts +0 -112
  165. package/tests/api/upload.test.ts +0 -103
  166. package/tests/api/vote.test.ts +0 -82
  167. package/tests/app/admin-feedback-detail-page.test.tsx +0 -25
  168. package/tests/app/admin-feedback-list-page.test.tsx +0 -25
  169. package/tests/app/admin-feedback-new-page.test.tsx +0 -25
  170. package/tests/app/health-route-helpers.test.ts +0 -27
  171. package/tests/app/login-page.test.ts +0 -26
  172. package/tests/app/portal-page.test.ts +0 -29
  173. package/tests/app/project-portal-overview.test.tsx +0 -25
  174. package/tests/app/widget-page-import.test.ts +0 -25
  175. package/tests/components/create-post-dialog-defaults.test.ts +0 -43
  176. package/tests/components/feedback/duplicate-suggestions-inline.test.tsx +0 -27
  177. package/tests/components/feedback/embedded-feedback-form.test.tsx +0 -96
  178. package/tests/components/feedback/feedback-detail.test.tsx +0 -25
  179. package/tests/components/feedback/feedback-stats.test.tsx +0 -49
  180. package/tests/components/feedback-bulk-actions.test.tsx +0 -39
  181. package/tests/components/feedback-i18n-keys.test.ts +0 -70
  182. package/tests/components/feedback-list-controls-compile.test.ts +0 -25
  183. package/tests/components/feedback-list-controls.test.tsx +0 -204
  184. package/tests/components/feedback-list-item.test.tsx +0 -67
  185. package/tests/components/landing/hero.test.tsx +0 -46
  186. package/tests/components/layout/language-switcher.test.tsx +0 -25
  187. package/tests/components/layout/sidebar.test.tsx +0 -157
  188. package/tests/components/login-form.test.ts +0 -25
  189. package/tests/components/organization-form.test.ts +0 -32
  190. package/tests/components/organization-switcher.test.ts +0 -25
  191. package/tests/components/pagination.test.tsx +0 -43
  192. package/tests/components/portal-overview.test.tsx +0 -25
  193. package/tests/components/profile-form.test.tsx +0 -139
  194. package/tests/components/role-selector.test.ts +0 -31
  195. package/tests/components/status-chart.test.tsx +0 -90
  196. package/tests/e2e/auth.e2e.ts +0 -323
  197. package/tests/e2e/feedback-actions.e2e.ts +0 -471
  198. package/tests/e2e/feedback-attachment.e2e.ts +0 -168
  199. package/tests/e2e/feedback-customer.e2e.ts +0 -226
  200. package/tests/e2e/feedback-management.e2e.ts +0 -565
  201. package/tests/e2e/feedback-submit.e2e.ts +0 -133
  202. package/tests/e2e/feedback-view.e2e.ts +0 -297
  203. package/tests/e2e/fixtures/test-data.ts +0 -235
  204. package/tests/e2e/health-check.e2e.ts +0 -230
  205. package/tests/e2e/helpers/test-utils-helpers.test.ts +0 -43
  206. package/tests/e2e/helpers/test-utils.ts +0 -298
  207. package/tests/e2e/integration-placeholders.e2e.ts +0 -199
  208. package/tests/e2e/organization.e2e.ts +0 -292
  209. package/tests/e2e/permissions.e2e.ts +0 -424
  210. package/tests/e2e/project-widget.e2e.ts +0 -63
  211. package/tests/feedback/filters.test.ts +0 -29
  212. package/tests/hooks/use-permissions.test.ts +0 -52
  213. package/tests/lib/ai/classifier.test.ts +0 -104
  214. package/tests/lib/ai/duplicate-detector.test.ts +0 -234
  215. package/tests/lib/attachments-schema.test.ts +0 -30
  216. package/tests/lib/auth/session.test.ts +0 -49
  217. package/tests/lib/auth-client.test.ts +0 -37
  218. package/tests/lib/auth-config.test.ts +0 -26
  219. package/tests/lib/feedback-prefill.test.ts +0 -52
  220. package/tests/lib/feedback-processor.test.ts +0 -41
  221. package/tests/lib/feedback-schema.test.ts +0 -33
  222. package/tests/lib/file-validator.test.ts +0 -48
  223. package/tests/lib/get-feedback-by-id.test.ts +0 -37
  224. package/tests/lib/invitations.test.ts +0 -35
  225. package/tests/lib/login-schema.test.ts +0 -36
  226. package/tests/lib/org-context.test.ts +0 -95
  227. package/tests/lib/organization-access.test.ts +0 -44
  228. package/tests/lib/organization-member-role-schema.test.ts +0 -41
  229. package/tests/lib/permissions.test.ts +0 -88
  230. package/tests/lib/portal-analytics.test.ts +0 -25
  231. package/tests/lib/portal-contributors.test.ts +0 -25
  232. package/tests/lib/portal-copy.test.ts +0 -27
  233. package/tests/lib/portal-i18n.test.ts +0 -30
  234. package/tests/lib/portal-leaderboard-settings.test.ts +0 -25
  235. package/tests/lib/portal-modules.test.ts +0 -25
  236. package/tests/lib/portal-seo.test.ts +0 -25
  237. package/tests/lib/portal-sharing.test.ts +0 -25
  238. package/tests/lib/portal-sorting.test.ts +0 -25
  239. package/tests/lib/portal-theme.test.ts +0 -25
  240. package/tests/lib/rate-limit.test.ts +0 -142
  241. package/tests/lib/resolve-locale.test.ts +0 -34
  242. package/tests/lib/services/backup.test.ts +0 -145
  243. package/tests/lib/user-organizations.test.ts +0 -42
  244. package/tests/lib/user-role-schema.test.ts +0 -33
  245. package/tests/lib/user-schema.test.ts +0 -25
  246. package/tests/setup.ts +0 -74
  247. package/vercel.json +0 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
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
+
3
16
  ## 0.4.0
4
17
 
5
18
  ### 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");