mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 19:01:08 +02:00
refactor(feedback): align package + DB enums, plan central hub
Macht @mana/feedback zur SSOT für alle Nutzer-Feedback-Categories und -Status — Voraussetzung dafür, dass Onboarding-Wishes, NPS, Churn-Feedback etc. künftig dort landen. - Status-Enum: DB-Werte umbenannt new/reviewed/done/rejected → submitted/under_review/completed/declined (Package gewinnt). PG≥10 ALTER TYPE … RENAME VALUE ist non-destructive. - Category 'praise' ins Package aufgenommen (war nur in DB). - Category 'onboarding-wish' neu in Package + DB für den Wish-Step. - Default status in DB: 'new' → 'submitted'. - CreateFeedbackInput.isPublic optional → Service reicht durch, default bleibt true; private Categories wie onboarding-wish setzen false. - Schema-Datei mit SSOT-Kommentar versehen, der Drift in Zukunft verhindert. Hand-authored Migration unter services/mana-analytics/drizzle/0001_*.sql weil drizzle-kit push Enum-Werte nicht zuverlässig umbenennt. Manuell einspielen vor nächstem db:push: psql "\$DATABASE_URL" -f services/mana-analytics/drizzle/0001_align-feedback-enums.sql Plan in docs/plans/feedback-hub.md (Phase 0–4); Phase 0 + 1 jetzt, 2-4 deferred. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bf3bca268a
commit
ba6274edbe
6 changed files with 339 additions and 7 deletions
|
|
@ -0,0 +1,66 @@
|
|||
-- 0001_align-feedback-enums.sql
|
||||
--
|
||||
-- Bringt die Postgres-Enums `feedback.feedback_category` und
|
||||
-- `feedback.feedback_status` mit dem `@mana/feedback`-Package in Einklang
|
||||
-- und legt die `onboarding-wish`-Kategorie für den letzten
|
||||
-- Onboarding-Schritt an.
|
||||
--
|
||||
-- Hand-authored, weil `drizzle-kit push` Enum-Werte nicht zuverlässig
|
||||
-- umbenennt. Apply manually before next `pnpm db:push`:
|
||||
--
|
||||
-- psql "$DATABASE_URL" -f services/mana-analytics/drizzle/0001_align-feedback-enums.sql
|
||||
--
|
||||
-- Idempotent: alle Schritte verwenden `IF EXISTS` / `IF NOT EXISTS`-Checks
|
||||
-- via DO-Blöcke, sodass Re-Runs nicht failen.
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. Status-Werte umbenennen, sodass sie zum Package passen.
|
||||
-- PostgreSQL ≥10 supportet ALTER TYPE … RENAME VALUE non-destructive.
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM pg_enum e
|
||||
JOIN pg_type t ON t.oid = e.enumtypid
|
||||
JOIN pg_namespace n ON n.oid = t.typnamespace
|
||||
WHERE t.typname = 'feedback_status' AND n.nspname = 'feedback' AND e.enumlabel = 'new'
|
||||
) THEN
|
||||
ALTER TYPE feedback.feedback_status RENAME VALUE 'new' TO 'submitted';
|
||||
END IF;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM pg_enum e
|
||||
JOIN pg_type t ON t.oid = e.enumtypid
|
||||
JOIN pg_namespace n ON n.oid = t.typnamespace
|
||||
WHERE t.typname = 'feedback_status' AND n.nspname = 'feedback' AND e.enumlabel = 'reviewed'
|
||||
) THEN
|
||||
ALTER TYPE feedback.feedback_status RENAME VALUE 'reviewed' TO 'under_review';
|
||||
END IF;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM pg_enum e
|
||||
JOIN pg_type t ON t.oid = e.enumtypid
|
||||
JOIN pg_namespace n ON n.oid = t.typnamespace
|
||||
WHERE t.typname = 'feedback_status' AND n.nspname = 'feedback' AND e.enumlabel = 'done'
|
||||
) THEN
|
||||
ALTER TYPE feedback.feedback_status RENAME VALUE 'done' TO 'completed';
|
||||
END IF;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM pg_enum e
|
||||
JOIN pg_type t ON t.oid = e.enumtypid
|
||||
JOIN pg_namespace n ON n.oid = t.typnamespace
|
||||
WHERE t.typname = 'feedback_status' AND n.nspname = 'feedback' AND e.enumlabel = 'rejected'
|
||||
) THEN
|
||||
ALTER TYPE feedback.feedback_status RENAME VALUE 'rejected' TO 'declined';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- 2. Default für status auf den neuen Wert setzen.
|
||||
ALTER TABLE feedback.user_feedback ALTER COLUMN status SET DEFAULT 'submitted';
|
||||
|
||||
-- 3. Neue Category für Onboarding-Wishes anlegen.
|
||||
ALTER TYPE feedback.feedback_category ADD VALUE IF NOT EXISTS 'onboarding-wish';
|
||||
|
||||
COMMIT;
|
||||
|
|
@ -13,22 +13,27 @@ import {
|
|||
|
||||
export const feedbackSchema = pgSchema('feedback');
|
||||
|
||||
// Enum values must mirror @mana/feedback's FeedbackCategory / FeedbackStatus
|
||||
// unions exactly. Renames or additions need a hand-authored SQL migration
|
||||
// under services/mana-analytics/drizzle/ (drizzle-kit push can't safely
|
||||
// rename enum values).
|
||||
export const feedbackCategoryEnum = pgEnum('feedback_category', [
|
||||
'bug',
|
||||
'feature',
|
||||
'improvement',
|
||||
'question',
|
||||
'praise',
|
||||
'onboarding-wish',
|
||||
'other',
|
||||
]);
|
||||
|
||||
export const feedbackStatusEnum = pgEnum('feedback_status', [
|
||||
'new',
|
||||
'reviewed',
|
||||
'submitted',
|
||||
'under_review',
|
||||
'planned',
|
||||
'in_progress',
|
||||
'done',
|
||||
'rejected',
|
||||
'completed',
|
||||
'declined',
|
||||
]);
|
||||
|
||||
export const userFeedback = feedbackSchema.table(
|
||||
|
|
@ -40,7 +45,7 @@ export const userFeedback = feedbackSchema.table(
|
|||
title: text('title'),
|
||||
feedbackText: text('feedback_text').notNull(),
|
||||
category: feedbackCategoryEnum('category').default('other').notNull(),
|
||||
status: feedbackStatusEnum('status').default('new').notNull(),
|
||||
status: feedbackStatusEnum('status').default('submitted').notNull(),
|
||||
isPublic: boolean('is_public').default(true).notNull(),
|
||||
adminResponse: text('admin_response'),
|
||||
voteCount: integer('vote_count').default(0).notNull(),
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export class FeedbackService {
|
|||
feedbackText: string;
|
||||
category?: string;
|
||||
title?: string;
|
||||
isPublic?: boolean;
|
||||
deviceInfo?: Record<string, unknown>;
|
||||
}
|
||||
) {
|
||||
|
|
@ -42,6 +43,10 @@ export class FeedbackService {
|
|||
title: title || data.feedbackText.slice(0, 80),
|
||||
feedbackText: data.feedbackText,
|
||||
category: (data.category as any) || 'other',
|
||||
// Honor explicit isPublic from caller; otherwise let the column
|
||||
// default (true) apply. Private intake categories like
|
||||
// 'onboarding-wish' should pass `false`.
|
||||
...(typeof data.isPublic === 'boolean' ? { isPublic: data.isPublic } : {}),
|
||||
deviceInfo: data.deviceInfo,
|
||||
})
|
||||
.returning();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue