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