@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
@@ -1,66 +0,0 @@
1
- # Design: Organization-Only Model (No Projects/Boards)
2
-
3
- **Date:** 2026-01-10
4
- **Status:** Approved
5
-
6
- ## Summary
7
- Move Echo to an organization-only model. Remove the “project” concept and any boards. Each organization owns exactly three resource areas: Feedback, Roadmap, and Changelog. Public portal becomes a single organization entry at `/<organizationSlug>`, with tabs switching among the three.
8
-
9
- ## Goals
10
- - Remove all project/board concepts from data model, routes, and UI.
11
- - Consolidate configuration at organization level (portal/widget settings, domain, visibility).
12
- - Keep organization isolation and permissions unchanged.
13
- - Ensure MVP: auto-create a default organization for new users.
14
-
15
- ## Non-Goals
16
- - Data migration from existing projects (data loss is acceptable per requirement).
17
- - Multi-portal or per-resource domains.
18
- - Multiple organizations per user experience redesign.
19
-
20
- ## Data Model Changes
21
- - Drop `projects` table and all `projectId` references.
22
- - Remove `projectId` fields, indexes, and foreign keys from other tables.
23
- - Store portal/widget configuration on organization level:
24
- - Option A (preferred): new `organization_settings` table.
25
- - Option B: add columns on `organizations`.
26
- - Feedback, roadmap, and changelog records are keyed by `organizationId`.
27
-
28
- ## Routing & UX
29
- - Public portal: `/<organizationSlug>`
30
- - Default view: Feedback
31
- - Tabs: Feedback / Roadmap / Changelog
32
- - Remove routes:
33
- - `/settings/projects`
34
- - `/settings/projects/new`
35
- - `/settings/projects/[projectSlug]`
36
- - `/widget/[organizationId]/[projectId]`
37
- - Add/update routes:
38
- - `/settings/organization`
39
- - `/settings/organization/portal`
40
-
41
- ## API Changes
42
- - Remove project CRUD APIs.
43
- - Update portal/widget APIs to be organization-scoped only.
44
- - Any endpoints that require `projectId` now infer by `organizationId`.
45
-
46
- ## Content Model
47
- - Feedback: organization-scoped list and detail views.
48
- - Roadmap: organization-scoped items and timeline.
49
- - Changelog: organization-scoped entries.
50
-
51
- ## Permissions
52
- - No change: permissions remain organization-scoped.
53
- - Admin-only access to organization settings and portal config.
54
-
55
- ## Data Loss & Rollout
56
- - Existing project data will be dropped.
57
- - Migration scripts should remove project-related tables/columns and cleanup foreign keys.
58
-
59
- ## Testing
60
- - Route access: no project pages remain.
61
- - Portal loads at `/<organizationSlug>` with tabs switching among sections.
62
- - Organization settings update portal config successfully.
63
- - Feedback list and detail work without `projectId`.
64
-
65
- ## Open Questions
66
- - Final choice: `organization_settings` vs adding columns on `organizations`.
@@ -1,433 +0,0 @@
1
- # Organization-Only Model Implementation Plan
2
-
3
- > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
-
5
- **Goal:** Remove project/board concepts and consolidate all data and UX at the organization level, with a public portal at `/<organizationSlug>` and three fixed sections: Feedback, Roadmap, Changelog.
6
-
7
- **Architecture:** Drop the `projects` table and all `projectId` references. Introduce organization-level settings for portal/widget/custom domain (new `organization_settings` table). Update routes, APIs, and UI to be organization-scoped only. Public portal uses org slug paths (`/<orgSlug>`, `/<orgSlug>/roadmap`, `/<orgSlug>/changelog`).
8
-
9
- **Tech Stack:** Next.js App Router, Drizzle ORM, PostgreSQL, TypeScript, Tailwind, Bun.
10
-
11
- ---
12
-
13
- ## Task 1: Add organization settings schema + drop project references in DB
14
-
15
- **Files:**
16
- - Create: `lib/db/schema/organization-settings.ts`
17
- - Modify: `lib/db/schema/organizations.ts`
18
- - Modify: `lib/db/schema/feedback.ts`
19
- - Modify: `lib/db/schema/index.ts`
20
- - Create: `lib/db/migrations/0019_remove_projects_add_org_settings.sql`
21
-
22
- **Step 1: Write failing schema test (optional if no schema tests exist)**
23
- - If schema tests exist, add a test in `tests/lib/organization-settings-schema.test.ts` to assert default config merging or type presence. Otherwise skip.
24
-
25
- **Step 2: Write organization settings schema**
26
- - Create `lib/db/schema/organization-settings.ts`:
27
- ```ts
28
- import { relations } from "drizzle-orm";
29
- import { index, jsonb, pgTable, text, timestamp, unique } from "drizzle-orm/pg-core";
30
- import { organizations } from "./organizations";
31
-
32
- export type WidgetConfig = {
33
- theme?: "light" | "dark" | "auto";
34
- primaryColor?: string;
35
- buttonText?: string;
36
- buttonPosition?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
37
- fields?: {
38
- showType?: boolean;
39
- showPriority?: boolean;
40
- showDescription?: boolean;
41
- requireEmail?: boolean;
42
- };
43
- types?: string[];
44
- customCSS?: string;
45
- };
46
-
47
- export type PortalThemeConfig = {
48
- mode?: "light" | "dark" | "system";
49
- primaryColor?: string;
50
- accentColor?: string;
51
- borderRadius?: "none" | "sm" | "md" | "lg" | "full";
52
- fontFamily?: string;
53
- customCSS?: string;
54
- };
55
-
56
- export type PortalCopyConfig = {
57
- title?: string;
58
- description?: string;
59
- ctaLabel?: string;
60
- emptyStateMessage?: string;
61
- successMessage?: string;
62
- placeholders?: {
63
- titleInput?: string;
64
- descriptionInput?: string;
65
- };
66
- };
67
-
68
- export type PortalSeoConfig = {
69
- metaTitle?: string;
70
- metaDescription?: string;
71
- ogImage?: string;
72
- favicon?: string;
73
- noIndex?: boolean;
74
- };
75
-
76
- export type PortalSharingConfig = {
77
- enabled?: boolean;
78
- allowPublicVoting?: boolean;
79
- allowPublicComments?: boolean;
80
- showVoteCount?: boolean;
81
- showAuthor?: boolean;
82
- socialSharing?: {
83
- twitter?: boolean;
84
- linkedin?: boolean;
85
- facebook?: boolean;
86
- };
87
- };
88
-
89
- export type PortalConfig = {
90
- theme?: PortalThemeConfig;
91
- copy?: PortalCopyConfig;
92
- seo?: PortalSeoConfig;
93
- sharing?: PortalSharingConfig;
94
- languages?: string[];
95
- defaultLanguage?: string;
96
- modules?: {
97
- feedback?: boolean;
98
- roadmap?: boolean;
99
- changelog?: boolean;
100
- help?: boolean;
101
- };
102
- };
103
-
104
- export const organizationSettings = pgTable(
105
- "organization_settings",
106
- {
107
- organizationId: text("organizationId")
108
- .notNull()
109
- .references(() => organizations.id, { onDelete: "cascade" })
110
- .primaryKey(),
111
- widgetConfig: jsonb("widgetConfig").$type<WidgetConfig>(),
112
- portalConfig: jsonb("portalConfig").$type<PortalConfig>(),
113
- customDomain: text("customDomain"),
114
- createdAt: timestamp("createdAt").defaultNow().notNull(),
115
- updatedAt: timestamp("updatedAt")
116
- .defaultNow()
117
- .$onUpdate(() => new Date())
118
- .notNull(),
119
- },
120
- (table) => ({
121
- orgIdx: index("idx_org_settings_orgId").on(table.organizationId),
122
- customDomainUnique: unique("unique_org_custom_domain").on(table.customDomain),
123
- })
124
- );
125
-
126
- export const organizationSettingsRelations = relations(organizationSettings, ({ one }) => ({
127
- organization: one(organizations, {
128
- fields: [organizationSettings.organizationId],
129
- references: [organizations.id],
130
- }),
131
- }));
132
-
133
- export type OrganizationSettings = typeof organizationSettings.$inferSelect;
134
- export type NewOrganizationSettings = typeof organizationSettings.$inferInsert;
135
- ```
136
-
137
- **Step 3: Remove `projectId` from feedback schema**
138
- - Update `lib/db/schema/feedback.ts`:
139
- - Remove import of `projects`.
140
- - Remove `projectId` column and `idx_feedback_projectId` index.
141
-
142
- **Step 4: Update schema index exports**
143
- - Remove `projects` export, add `organization-settings` export in `lib/db/schema/index.ts`.
144
-
145
- **Step 5: Write migration**
146
- - Create `lib/db/migrations/0019_remove_projects_add_org_settings.sql`:
147
- ```sql
148
- DROP TABLE IF EXISTS "projects" CASCADE;
149
- ALTER TABLE "feedback" DROP COLUMN IF EXISTS "projectId";
150
- DROP INDEX IF EXISTS "idx_feedback_projectId";
151
-
152
- CREATE TABLE "organization_settings" (
153
- "organizationId" text PRIMARY KEY REFERENCES "organizations"("id") ON DELETE cascade,
154
- "widgetConfig" jsonb,
155
- "portalConfig" jsonb,
156
- "customDomain" text,
157
- "createdAt" timestamp DEFAULT now() NOT NULL,
158
- "updatedAt" timestamp DEFAULT now() NOT NULL
159
- );
160
- CREATE INDEX "idx_org_settings_orgId" ON "organization_settings" ("organizationId");
161
- ALTER TABLE "organization_settings" ADD CONSTRAINT "unique_org_custom_domain" UNIQUE ("customDomain");
162
- ```
163
-
164
- **Step 6: Commit**
165
- ```bash
166
- git add lib/db/schema/organization-settings.ts lib/db/schema/feedback.ts lib/db/schema/index.ts lib/db/migrations/0019_remove_projects_add_org_settings.sql
167
-
168
- git commit -m "feat: add organization settings and drop project schema"
169
- ```
170
-
171
- ---
172
-
173
- ## Task 2: Replace portal settings service with organization-scoped service
174
-
175
- **Files:**
176
- - Modify: `lib/services/portal-settings.ts`
177
-
178
- **Step 1: Write failing test for portal settings (if applicable)**
179
- - Add/adjust test in `tests/lib/portal-settings.test.ts` (create if missing) to assert organization-scoped read/write.
180
-
181
- **Step 2: Update service implementation**
182
- - Replace `projectId` params with `organizationId` and query `organizationSettings`:
183
- ```ts
184
- import { organizationSettings, PortalConfig } from "@/lib/db/schema";
185
-
186
- export async function getPortalSettings(organizationId: string): Promise<PortalConfig | null> { /* ... */ }
187
- export async function updatePortalSettings<T extends keyof PortalConfig>(
188
- organizationId: string,
189
- section: T,
190
- data: PortalConfig[T]
191
- ): Promise<{ success: boolean; error?: string }> { /* ... */ }
192
- export async function updateFullPortalConfig(
193
- organizationId: string,
194
- config: PortalConfig
195
- ): Promise<{ success: boolean; error?: string }> { /* ... */ }
196
- ```
197
- - Ensure `organization_settings` row exists (insert on first write if missing).
198
-
199
- **Step 3: Commit**
200
- ```bash
201
- git add lib/services/portal-settings.ts
202
-
203
- git commit -m "refactor: scope portal settings to organization"
204
- ```
205
-
206
- ---
207
-
208
- ## Task 3: Remove project APIs and adjust feedback API
209
-
210
- **Files:**
211
- - Delete: `app/api/projects/route.ts`
212
- - Delete: `app/api/projects/[projectId]/route.ts`
213
- - Modify: `app/api/feedback/route.ts`
214
- - Modify: `app/api/feedback/handler.ts`
215
- - Modify: `lib/validators/feedback.ts`
216
-
217
- **Step 1: Update feedback validation**
218
- - Remove `projectId` from `feedbackSchema`.
219
-
220
- **Step 2: Update feedback POST handler**
221
- - Remove `projectId` insert in `app/api/feedback/handler.ts`.
222
-
223
- **Step 3: Update feedback GET handler**
224
- - Remove `projectId` filter logic from `app/api/feedback/route.ts`.
225
-
226
- **Step 4: Remove project APIs**
227
- - Delete both project route files and update any import references.
228
-
229
- **Step 5: Commit**
230
- ```bash
231
- git add app/api/feedback/route.ts app/api/feedback/handler.ts lib/validators/feedback.ts
232
-
233
- git rm app/api/projects/route.ts app/api/projects/[projectId]/route.ts
234
-
235
- git commit -m "refactor: remove project APIs and projectId in feedback"
236
- ```
237
-
238
- ---
239
-
240
- ## Task 4: Update portal routing to organization-only public paths
241
-
242
- **Files:**
243
- - Create: `app/[organizationSlug]/page.tsx`
244
- - Create: `app/[organizationSlug]/roadmap/page.tsx`
245
- - Create: `app/[organizationSlug]/changelog/page.tsx`
246
- - Delete: `app/portal/page.tsx`
247
- - Delete: `app/portal/[orgSlug]/[projectSlug]/page.tsx`
248
- - Modify: `components/portal/portal-shell.tsx`
249
- - Modify: `components/portal/portal-nav.tsx`
250
-
251
- **Step 1: Add org portal pages**
252
- - `app/[organizationSlug]/page.tsx` should load org by slug and render Feedback tab.
253
- - Roadmap/Changelog pages can be placeholder components for now (e.g. empty states) but must render PortalShell with proper section links.
254
-
255
- **Step 2: Update PortalShell to accept only `organizationId`**
256
- - Remove `projectId` prop; pass organizationId only.
257
-
258
- **Step 3: Ensure PortalNav highlights active tab by pathname**
259
- - Keep `usePathname` and ensure section hrefs are `/${orgSlug}`, `/${orgSlug}/roadmap`, `/${orgSlug}/changelog`.
260
-
261
- **Step 4: Commit**
262
- ```bash
263
- git add app/[organizationSlug]/page.tsx app/[organizationSlug]/roadmap/page.tsx app/[organizationSlug]/changelog/page.tsx components/portal/portal-shell.tsx components/portal/portal-nav.tsx
264
-
265
- git rm app/portal/page.tsx app/portal/[orgSlug]/[projectSlug]/page.tsx
266
-
267
- git commit -m "feat: move public portal to organization routes"
268
- ```
269
-
270
- ---
271
-
272
- ## Task 5: Update widget and embedded feedback to org-only
273
-
274
- **Files:**
275
- - Modify: `app/widget/[organizationId]/[projectId]/page.tsx` → move to `app/widget/[organizationId]/page.tsx`
276
- - Modify: `components/feedback/embedded-feedback-form.tsx`
277
- - Modify: `components/widget/widget-form.tsx`
278
- - Modify: `components/project/embed-code-generator.tsx` (or delete if unused)
279
-
280
- **Step 1: Replace widget route**
281
- - New route: `app/widget/[organizationId]/page.tsx` reads organization settings and portal/widget configs.
282
- - Update embed code to use `/widget/${organizationId}` only.
283
-
284
- **Step 2: Update embedded feedback form**
285
- - Remove `projectId` prop and any submit payload usage.
286
-
287
- **Step 3: Commit**
288
- ```bash
289
- git add app/widget/[organizationId]/page.tsx components/feedback/embedded-feedback-form.tsx components/widget/widget-form.tsx
290
-
291
- git rm app/widget/[organizationId]/[projectId]/page.tsx
292
-
293
- git commit -m "refactor: org-only widget and embedded feedback"
294
- ```
295
-
296
- ---
297
-
298
- ## Task 6: Remove project UI and update settings to organization portal
299
-
300
- **Files:**
301
- - Delete: `components/project/*`
302
- - Delete: `app/(dashboard)/settings/projects/**`
303
- - Modify: `components/layout/sidebar.tsx`
304
- - Modify: `components/layout/mobile-sidebar.tsx`
305
- - Modify: `components/layout/dashboard-layout.tsx`
306
- - Modify: `app/(dashboard)/layout.tsx`
307
- - Modify: `components/settings/settings-sidebar.tsx`
308
- - Create: `app/(dashboard)/settings/organization/portal/page.tsx`
309
- - Modify: `components/portal/portal-settings-shell.tsx`
310
- - Modify: `components/portal/portal-overview.tsx`
311
- - Modify: portal settings forms to accept `organizationId` instead of `projectId`
312
-
313
- **Step 1: Remove project UI**
314
- - `git rm -r components/project app/(dashboard)/settings/projects`
315
-
316
- **Step 2: Update layout/sidebar to remove project list**
317
- - Remove `projects` props and related UI sections.
318
-
319
- **Step 3: Update portal settings UI for organization**
320
- - `PortalSettingsShell` becomes org-only (no selector).
321
- - Update `PortalModulesPanel` + settings forms to accept `organizationId`.
322
- - Add new route `/settings/organization/portal` to render portal settings with organization context.
323
-
324
- **Step 4: Commit**
325
- ```bash
326
- git add components/layout/sidebar.tsx components/layout/mobile-sidebar.tsx components/layout/dashboard-layout.tsx app/(dashboard)/layout.tsx components/portal/portal-settings-shell.tsx components/portal/portal-overview.tsx components/portal/portal-modules-panel.tsx components/portal/settings-forms/* app/(dashboard)/settings/organization/portal/page.tsx components/settings/settings-sidebar.tsx
327
-
328
- git rm -r components/project app/(dashboard)/settings/projects
329
-
330
- git commit -m "refactor: remove project UI and move portal settings to organization"
331
- ```
332
-
333
- ---
334
-
335
- ## Task 7: Update internal services and routes for organization context
336
-
337
- **Files:**
338
- - Delete: `lib/projects/get-projects.ts`
339
- - Delete: `lib/projects/get-project-for-settings.ts`
340
- - Delete: `lib/routes/projects.ts`
341
- - Modify: `app/api/internal/domain-lookup/route.ts`
342
- - Modify: `lib/services/github-sync.ts` (if it references projects)
343
-
344
- **Step 1: Remove project helper modules**
345
- - `git rm lib/projects/get-projects.ts lib/projects/get-project-for-settings.ts lib/routes/projects.ts`
346
-
347
- **Step 2: Update domain lookup**
348
- - Query `organizationSettings.customDomain` joined to `organizations`.
349
- - Response should include `orgSlug` and `organizationId` only.
350
-
351
- **Step 3: Commit**
352
- ```bash
353
- git add app/api/internal/domain-lookup/route.ts
354
-
355
- git rm lib/projects/get-projects.ts lib/projects/get-project-for-settings.ts lib/routes/projects.ts
356
-
357
- git commit -m "refactor: drop project helpers and update domain lookup"
358
- ```
359
-
360
- ---
361
-
362
- ## Task 8: Clean up tests for project removal + add org-portal tests
363
-
364
- **Files:**
365
- - Delete: `tests/api/projects.test.ts`
366
- - Delete: `tests/lib/routes/projects.test.ts`
367
- - Delete or update: `tests/components/portal-project-switcher.test.tsx`
368
- - Update: `tests/app/portal-page.test.ts`
369
- - Update: `tests/components/layout/sidebar.test.tsx`
370
- - Update: `tests/components/project-settings-tabs.test.tsx`
371
- - Update: any project-based tests to org equivalents
372
-
373
- **Step 1: Update portal page test**
374
- - Point to new `app/[organizationSlug]/page.tsx` exports (or test for sections construction via helper).
375
-
376
- **Step 2: Remove project-only tests**
377
- - Remove tests that validate project routes/components.
378
-
379
- **Step 3: Add org portal nav test**
380
- - Add a test that ensures portal sections are `/${orgSlug}`, `/${orgSlug}/roadmap`, `/${orgSlug}/changelog`.
381
-
382
- **Step 4: Commit**
383
- ```bash
384
- git add tests/app/portal-page.test.ts tests/components/layout/sidebar.test.tsx
385
-
386
- git rm tests/api/projects.test.ts tests/lib/routes/projects.test.ts tests/components/portal-project-switcher.test.tsx tests/components/project-settings-tabs.test.tsx
387
-
388
- git commit -m "test: align portal and layout tests to org-only model"
389
- ```
390
-
391
- ---
392
-
393
- ## Task 9: Docs cleanup (minimal)
394
-
395
- **Files:**
396
- - Modify: `docs/route-role-visibility.md`
397
- - Modify: `docs/user-story-tracking.md`
398
-
399
- **Step 1: Replace project routes with organization routes**
400
- - Remove references to `/settings/projects/*` and `/widget/[organizationId]/[projectId]`.
401
- - Add `/settings/organization/portal` and `/<organizationSlug>`.
402
-
403
- **Step 2: Commit**
404
- ```bash
405
- git add docs/route-role-visibility.md docs/user-story-tracking.md
406
-
407
- git commit -m "docs: update routes for organization-only model"
408
- ```
409
-
410
- ---
411
-
412
- ## Task 10: Verification
413
-
414
- **Step 1: Run tests (expect current baseline lint warnings still present)**
415
- ```bash
416
- bun run lint
417
- bun test
418
- ```
419
- Expected: lint may still warn as before; new tests should pass.
420
-
421
- **Step 2: Manual smoke**
422
- - Visit `/settings/organization/portal` and confirm portal settings render.
423
- - Visit `/<organizationSlug>` and see tabs for Feedback/Roadmap/Changelog.
424
- - Visit `/widget/<organizationId>` and submit feedback (no projectId in payload).
425
-
426
- ---
427
-
428
- Plan complete and saved to `docs/plans/2026-01-10-organization-only-implementation.md`. Two execution options:
429
-
430
- 1. Subagent-Driven (this session) - I dispatch fresh subagent per task, review between tasks, fast iteration
431
- 2. Parallel Session (separate) - Open new session with executing-plans, batch execution with checkpoints
432
-
433
- Which approach?
@@ -1,18 +0,0 @@
1
- # Plan
2
-
3
- We will move Portal settings under each project, create new project-scoped Portal routes with an overview page, migrate existing Portal settings pages into the new structure, and update navigation so Portal is no longer a global settings section.
4
-
5
- ## Scope
6
- - In: project-scoped Portal routes, Portal overview page, migration of Portal settings pages, navigation updates
7
- - Out: new backend fields/logic, Portal front-end public UI changes, analytics on overview
8
-
9
- ## Action items
10
- [ ] Review current Portal settings pages and project settings page to confirm fields and entry points
11
- [ ] Add project-scoped Portal routes and an overview page with portal sub-nav
12
- [ ] Migrate existing Portal settings pages to new routes (experience/growth/access/modules)
13
- [ ] Re-map fields so access page holds visibility/permission/noindex, growth holds sharing + SEO
14
- [ ] Update global settings sidebar and project settings entry to link Portal
15
- [ ] Manually verify routing, permissions, and project context switching
16
-
17
- ## Open questions
18
- - None (decisions: remove /settings/portal-* routes, modules as overview fold, no analytics on overview)