Skip to main content

RFC Review: Embeddable Create-Ticket Form in CDP Customer Detail (Web)

Companion review for rfc-create-ticket-embeddable-web.md, produced by the rfc-reviewer skill. Lives beside the RFC; valid only for the RFC revision in reviewed_rfc_last_updated (2026-06-30 / d656b29).

Executive Summary

  • Overall Score: 8.0/10
  • Rating: Strong
  • RFC Type: frontend
  • Sub-Type: new-feature
  • Assessment Confidence: High
  • Applied Caps/Gates: none triggered (no category < 5.0; PRT/TDC/CNT/FMC all above their cap thresholds)
  • Implementation Readiness Verdict: HOLD (partial-proceed) — chunks 1–3 PROCEED today; chunks 4–6 BLOCKED on CRM dependencies OQ-1 / OQ-2 / OQ-contract.
  • Report Path: cdp/create-ticket-from-cdp/rfcs/rfc-create-ticket-embeddable-web-review.md
  • RFC Author: Jovi (CDP Frontend) | Reviewed: 2026-07-01

This is an unusually complete, evidence-grounded frontend RFC. Every in-repo code anchor it cites was verified against the live qontak-customer-fe checkout and is accurate (sandbox attrs, origin guard, the Deal embed's token/customer_id/source URL params, the Notes.vue permission gate, FeatureFlagStore, both config keys). For the CDP-owned surface an agent can implement chunks 1–3 (UI shell, permission/flag gate, "+" menu) directly from §2.A/2.D/4.C without asking a question. The biggest strength is the bidirectional PRD traceability + verified Repo Reading Guide; the biggest gap is that the highest-stakes contract — the cross-origin postMessage payload — is explicitly provisional (not frozen by CRM) and the embed it consumes is OUT of CRM Phase 1, so chunks 4–6 cannot be built correctly today. The one thing that must change before full agentic execution: CRM must (a) commit the CDP-reusable embed to a phase, (b) confirm in-iframe auth, and (c) freeze the typed contract — at which point §2.A stops being provisional. The RFC honestly sets §7 = no and this review agrees.


Quick Verdict

Why this RFC can be implemented agentically (chunks 1–3, today):

  • Full TypeScript contracts for the CDP-owned side (props, emits, panel state machine) in Detail 2.A, plus a file-by-file scope map (Detail 2.D) and per-chunk verifiable acceptance criteria (Detail 4.C).
  • Every pattern to mirror is named and verified against real source (Detail 2.0 Source Verification — all anchors confirmed in qontak-customer-fe).

Why this RFC will cause agent guessing or rework (chunks 4–6, today):

  • The EMBED_INIT / TICKET_CREATED / … payload field names in §2.A are taken from the PRD, not a frozen CRM contract (the RFC flags this itself) — an agent building chunk 4 now may build to field names that change.
  • The embed endpoint /embed/ticket/create and its in-iframe auth are unbuilt / OUT of CRM Phase 1 (OQ-1/OQ-2) — there is nothing to integrate against.

Findings Ledger (carry-forward)

Stable, never-renumbered finding ids. R1 (first cycle) — all findings newly minted. REV-1…REV-4, REV-6, REV-8…REV-10 formalize the RFC's own §5 OQs with stable ids; REV-5 and REV-7 are net-new findings from this review (not in the RFC's OQ list).

IDSeverityFinding (one line)RFC locationStatusFirst seenResolved inEvidence / fix
REV-1blockerCRM CDP-reusable embed is OUT of Phase 1 — chunks 4–6 have nothing to integrate against§1 Dependencies, §5 OQ-1openR1External (PM + CRM). CDP can ship only chunks 1–3 behind an OFF flag until CRM commits the embed to a phase.
REV-2blockerQontak One in-iframe auth unconfirmed (v2.8 JWT vs Mekari SSO) — create call may 401§3 Security, §5 OQ-2openR1External (CRM + Platform). Headline risk; confirm SSO flows into the iframe before chunk 4.
REV-3blockerpostMessage payload field names are provisional, not frozen by CRM§2.A note, §5 OQ-contractopenR1CRM must freeze EMBED_INIT/TICKET_CREATED/TICKET_CREATE_ERROR/EMBED_CLOSE/EMBED_RESIZE. Until then §2.A is provisional.
REV-4majorCDP embed_source (embed-web-cdp) not yet in BE ALLOWED_EMBED_SOURCESdata_source coerced to embed-web-chat§5 OQ-3, Detail 1.C S05openR1External (CRM Backend). Gates TCKT-S05 attribution only; does not block create.
REV-5minorInbound message handler validates event.origin + payload.version === 1 but not payload completeness — a malformed TICKET_CREATED (e.g. missing ticketId) is not guarded§2.2, Detail 2.A, §3 SecurityopenR1Net-new. Add a payload-shape guard (required-field check) before side effects; on malformed → treat as TICKET_CREATE_ERROR/no-op + log. Add a Vitest case.
REV-6minorAnalytics naming unresolved: PRD snake_case vs repo '[Qontak One] [Customer] …' convention§3 Monitoring note, §5openR1Confirm with data team whether to wrap snake_case under a '[Qontak One] [Customer] Create Ticket Embed …' label.
REV-7minorNFS performance budget defers to "app defaults" — no concrete LCP/INP/CLS numbers or browser-version matrix§3 Performance RequirementopenR1Net-new. Acceptable for an additive lazy panel, but state the inherited numeric targets + browser matrix explicitly so test assertions have a number.
REV-8minorAuto-associate vs fallback POST undetermined — gates whether chunk 6 ships§5 OQ-6, Detail 1.C S04openR1Confirm with CRM whether the CDP path auto-associates the contact; if yes, chunk 6 is dead code.
REV-9minorFigma frames pending for both surfaces§1 Design References, §5 OQ-8openR1Mitigated — UI shell fully determined by the in-repo Deal pattern; pixel polish + menu copy/icon wait on Figma.
REV-10minorExact ticket-create permission key for the CDP entry unnamed§5 OQ-4openR1Mirror Notes.vue canAddNotes once CRM/CDP name the CanCan key; put it in a sibling constants file.

Ledger summary: 10 open (3 blocker / 1 major / 6 minor), 0 fixed (first cycle), 0 accepted-risk. REV-5 and REV-7 should be promoted into the RFC's §5 Open-Questions table — the other eight already live there and are now id-stamped.


PRD → RFC Traceability Matrix

Two PRDs linked (prd-create-ticket-embeddable-web.md SUPPORT + prd-create-ticket-from-cdp-anchor.md). Detail 1.A provides forward, reverse, surface, role, and §-by-§ coverage.

PRD ElementRFC SectionCoverage
TCKT-S01 (open embed)§2.A, §2.C, Detail 1.C, 4.C #1–#3Full
TCKT-S02 (auto-fill via EMBED_INIT)§2.A, §2.2, 4.C #4Full (contract provisional — REV-3)
TCKT-S03 (confirm + refresh)§2.2, §3.A, 4.C #4–#5Full (payload-completeness guard missing — REV-5)
TCKT-S04 (associate created ticket)§2.4, 4.C #6Full, conditional on OQ-6 (REV-8)
TCKT-S05 (data_source = CDP)§2.4, §5Full (cross-squad — correctly n/a on CDP; depends REV-4)
TCKT-S06 (pipeline/layout from CRM)§1 Out of ScopeFull (cross-squad — CRM-owned)
TCKT-S07-NEG (no create w/o perm/flag)§2.D, §4.A, 4.C #2Full
PRD §§ HEADER, 2–15Detail 1.A PRD Section Coverage tableFull — all 15 sections mapped
RFC decisions D-1…D-6Detail 1.B reverse matrixFull — each traces to a PRD AC/need

Summary: 7 of 7 PRD stories fully covered (S05/S06 correctly mapped as cross-squad n/a — covered in CRM RFC), 0 partial, 0 missing. 0 RFC decisions without PRD justification (no scope creep).


Scorecard

Frontend Scorecard (11 categories)

CategoryScoreEvidence-Based Rationale
PRT — PRD Traceability9.0Detail 1.A: forward (PRD AC→§→file), reverse (decision→AC), UI/role/section coverage, per-story map (1.C) covering all 7 stories once. Bidirectional, no silent drops.
TDC — Technical Decisions7.5Detail 1.B: 6 decisions, each chosen option + alternatives + grounded rejection. CDP-side fully resolved; D-2/D-3 specify a contract that is provisional pending CRM freeze (REV-3) — a real gap for chunks 4–6, honestly owned cross-squad.
CNT — Contract Specificity7.5Detail 2.A: full TS interfaces (props, emits, EmbedInit/Ready/Created/Error/Close/Resize) + state shape + Detail 2.B data-fetching strategy (Pinia + $customFetch, imperative refetch, no SWR/optimistic). Richly specified — but the embed-facing half is flagged provisional (REV-3), the #1 weighted category's central risk.
SCB — Scope Boundaries9.0Detail 2.D: files to create / modify / explicitly NOT touched (AssociatedDeals.vue, associate-existing flow, TicketStore write paths) + shared-component impact. Agent can produce a file-by-file plan.
DEP — Dependencies9.0§1 Dependencies table + Detail 2.4: every dep has owner + availability + blocking flag; correctly flags the core embed as OUT of CRM Phase 1. Config keys (CRM_V3_EMBED_URL, CUSTOMER_360_CRM_URL) verified to exist.
FMC — Failure Mode Coverage8.5Detail 3.A failure catalog (401/403/404/429/500/timeout/offline/retry per call), 3.B error-message catalog (code→i18n→surface), narrative (double-click, dup TICKET_CREATED, nav-during-embed cleanup), origin+version spoof guard. Gap: no malformed-payload guard (REV-5).
NFS — Non-Functional Specificity7.5A11y (3.C) and security (threat model) strong and specific; performance defers to "app defaults" with no numbers and browser matrix only as "app matrix" (REV-7). Justified for a lazy additive panel but thin on quantification.
TPS — Test Plan Specificity8.5Detail 4.B real commands (verified in package.json), per-story Vitest ACs in 1.C ("postMessage once to new URL(CRM_V3_EMBED_URL).origin; not called for spoofed origin"), per-chunk ACs in 4.C, E2E correctly deferred to Lane-C. QA can write the suite.
ROL — Rollout & Rollback8.5§4: flag default OFF, named stages, stop conditions (>10%/>5%/origin-bypass), instant flag-OFF rollback, blast radius; 4.A config contract; 4.D verification + rollback recipe. Schedule/PICs correctly deferred to delivery/.
OBS — Observability8.0§3: 5 named Mixpanel events with properties + triggers, Datadog RUM for errors, alert thresholds + #cdp-ops channel. Naming-convention reconciliation open (REV-6).
CPA — Pattern Alignment9.0Detail 2.0 Repo Reading Guide + Patterns table + Source Verification — all anchors verified against live repo. Mirrors Deal embed, Notes gate, FeatureFlagStore, useMixpanel. The single deviation (typed version:1 vs legacy {msg}) is explicitly justified (D-2/D-3).

Overall: 8.0 (judgment, not mean). Spec quality is Agentic-Ready-grade; the score sits just under 8.5 because the highest-weighted category (CNT) carries a documented provisional-contract risk and three blocking external OQs gate half the execution plan. No score caps applied.


Decision Closure Assessment

Decision Index

#DecisionStatusCritical Gaps
D-1Consume CRM embed, build nothing CDP-nativeResolvednone
D-2Use typed versioned postMessage contractPartialInterface provisional until CRM freezes contract (REV-3)
D-3Pass contact via EMBED_INIT keyed on qontakCustomerId (no token param)PartialSame provisional contract + auth assumption depends on OQ-2 (REV-2)
D-4data_source set server-side from allow-listed embed_sourceResolvedDepends on CRM allow-list (REV-4) but CDP decision itself is closed
D-5Degrade gracefully to associate-existingResolvednone
D-6New component TicketEmbedPanel.vue vs inlineResolvednone (explicitly reversible)

Aggregate: 4 Resolved, 2 Partial, 0 Dangling.


Decision: D-2 — Typed versioned postMessage contract

Status: Partial

What was decided: Adopt EMBED_INIT ⇄ TICKET_CREATED/TICKET_CREATE_ERROR/EMBED_CLOSE/EMBED_RESIZE, version: 1, origin-validated — superseding the Deal embed's legacy {msg} string contract.

Alternatives considered: Mirror the shipped Deal {msg} string contract — rejected because the CRM FE RFC defines a typed payload and {msg} "would not interoperate with the new Phase-1 component." Grounded and correct.

Grounding in existing code: Strong — mirrors AssociatedDeals.vue origin guard (verified L292) but tightens with a version check; the {msg} precedent ('Deal successfully created') verified at L301.

Interface specification: Fully shaped in Detail 2.A as TypeScript types — but the field names are sourced from the PRD, not a frozen CRM contract (the RFC says so explicitly). This is the gap.

Failure handling: Spoofed origin / wrong version → no-op + cdp_ticket_embed_init_dropped. Missing: malformed-but-valid-origin payload (REV-5).

Challenge results:

  • Scale: fine — event-driven, single embed per panel.
  • Reversibility: low cost to change field names if caught before chunk 4; high cost if built first and the frozen contract differs. This is why chunk 4 must wait on REV-3.
  • Consistency: consistent with D-3.
  • Agent implementability: an agent could generate the interfaces verbatim — and that is the risk: it would generate a provisional interface confidently.

Gaps and suggestions: Block chunk 4 until CRM freezes the contract; until then keep §2.A labelled provisional (already done). Add the payload-completeness guard (REV-5).


Decision: D-3 — Contact via EMBED_INIT, no token URL param

Status: Partial

What was decided: Pass contact context through EMBED_INIT keyed on qontakCustomerId; the embed authenticates itself from the host session (direct JWT Bearer), so CDP does not append a token query param the way the Deal embed does.

Alternatives considered: token + customer_id URL params as AssociatedDeals.vue does — verified real (L170–172: token, customer_id, source=cdp). Rejected per the CRM BE RFC's direct-JWT model. Well-grounded.

Interface specification: EMBED_INIT payload typed in §2.A (provisional).

Failure handling: OQ-2 — if Qontak One SSO does not flow into the iframe, the create call 401s. The RFC names this the "headline blocking risk" (REV-2) but cannot resolve it CDP-side.

Challenge results:

  • Reversibility: if auth turns out to need a token param after all, this flips back to the Deal pattern — common/constants/auth.ts TOKEN_KEY = 'global_sso_token' (verified L1) is already cited as the fallback. Reasonable hedge.
  • Agent implementability: an agent cannot verify the auth model from this repo; it must trust the assumption. Blocked by REV-2.

Gaps and suggestions: Confirm OQ-2 with CRM + Platform before chunk 4. The fallback path is already identified, which de-risks reversal.


Decisions D-1, D-4, D-5, D-6 — Resolved (abbreviated)

  • D-1 (consume vs build native): chosen + alternative rejected (duplicates CRM logic, perpetuates parity-lag); grounded in the anchor PRD. No interface to pin on CDP side. Resolved.
  • D-4 (data_source server-side from allow-listed embed_source): correctly identifies CDP cannot influence the field (verified — Deal sends source=cdp client-side, overwritten server-side). CDP decision closed; CRM allow-list is the dependency (REV-4). Resolved.
  • D-5 (graceful degrade to associate-existing): additive, entry hidden when unavailable; the associate path "must never regress." Resolved — and the strongest safety property in the RFC.
  • D-6 (extract TicketEmbedPanel.vue vs inline): chosen for testability of the heavier typed handler; explicitly "reversible." Resolved.

UI State Audit

ComponentLoadingEmptyErrorPartialSuccessAssessment
TicketEmbedPanel.vue (new)defined (spinner until EMBED_READY/timeout)n/a (CRM form always renders once ready)defined (load-fail / TICKET_CREATE_ERROR → inline + retry + associate hint)n/a (single embed)defined (TICKET_CREATED → close + refresh + toast)5/5 (empty/partial justified n/a)
AssociatedTickets.vue (existing list)defined (existing skeleton)defined (existing "No tickets yet")defined (existing toast)defined (existing infinite-scroll)defined (refreshed list)5/5

Summary: 2 of 2 components have all applicable states defined (Detail 2.C). The two n/as are correctly justified, not omissions.


Performance Budget Check

MetricTargetBaselineSourceAssessment
LCP / INP / CLS"inherit app defaults (no new budget)"not statedvague — no numbers (REV-7); defensible for a lazy panel but un-assertable in tests
Bundle size delta"negligible — one small SFC, no new dependency"reasoning, not measuredadequate (reuses Pixel3/Pinia/useCustomConfig — no new dep, verified)
Code-splittingcomponent-level (panel mounts on open)§3adequate
Browser support"inherits the app matrix (Nuxt 4 / Vue 3)"§3vague — no explicit version matrix (REV-7)

Lazy-render + no-new-dependency claims are sound; the only gap is numeric targets for test assertions. Low-stakes for this feature.


Accessibility Review

AspectSpecified?DetailsAssessment
Keyboard navigation flowyes"+" popover navigable; panel reachableadequate
Focus management (modal/route)yesfocus moves into panel on open; Esc/back-arrow returns focus to "+" triggeradequate — explicitly avoids the focus-return trap
ARIA labelsyesiframe title="Create Ticket"; error role="alert"adequate
Heading hierarchynonot addressedminor — panel is shallow; low risk
Color contrastyesPixel3 tokens (DS-verified)adequate
Motion sensitivityyesno custom animation introducedadequate
Screen reader behaviorpartialiframe title only; embed internals are CRM'sacceptable (cross-origin boundary)

A11y is one of the better-specified sections; only heading hierarchy is unmentioned (low impact).


Pattern Alignment Check

PatternRFC ApproachAssessment
Pinia setup stores (storeToRefs)followsverified — matches TicketStore/UserStore
Feature-scoped component folderfollowsTicketEmbedPanel.vue beside AssociatedTickets.vue
Pixel3 + panda css() stylingfollowsmatches AssociatedDeals.vue
toastNotify error/toastfollowsverified L208/L140 in AssociatedTickets.vue
Permission gate (canAddNotes)extendsmirrors Notes.vue L83–96 (verified) for canCreateTicket
Feature flag (featureFlags[code])extendsadds code to FeatureFlags + DEFAULT_FEATURE_FLAGS (verified L36/L49)
iframe embed + origin-validated listenerreplaces contractmirrors Deal shell but swaps legacy {msg} + URL-param contract for typed version:1 + EMBED_INITexplicitly justified (D-2/D-3), not a silent parallel system
Analytics (useMixpanel().track)follows, naming TBDevent names need convention reconciliation (REV-6)

No silent pattern drift. The one replacement is deliberate, documented, and the old pattern (Deal embed) is left untouched (Files explicitly NOT touched).


Mermaid Validity

4/4 blocks parse (mermaid v11 headless via jsdom; mmdc itself can't launch Chromium in this sandbox — same limitation the author recorded). Blocks: Repo Map (flowchart LR), Component diagram (flowchart TB), Embed-panel state machine (stateDiagram-v2), Sequence (happy + failure). No semicolons in sequence notes, all ()// in node labels are quoted, no </> in state transition labels. No findings.


Source Verification (independent re-check)

Every anchor in the RFC's Detail 2.0 Source Verification table was independently re-checked against the live qontak-customer-fe sibling checkout — all confirmed accurate (line numbers within ±1–2 where they drift):

ClaimVerified
AssociatedDeals.vue sandbox L15 / referrerpolicy L16 / createDealUrl L162 / origin guard L292 / 'Deal successfully created' L301 / listener add L368 remove L372 / https force L167
Deal embed appends token + customer_id + source=cdp URL params (the D-3 deviation baseline)✅ L170–172
AssociatedTickets.vue associate POST L182 / fetchTicketsAssociated L241 / markContactUpdated L202 / toastNotify L208
TicketStore.fetchTicketsAssociated L168 / qontak_customer_id L153 / /v1/tickets on CUSTOMER_360_CRM_URL
Notes.vue canAddNotes L83–96 / is_enabled === true L96 / ADD_NOTES_PERMISSION L27
auth.ts TOKEN_KEY = 'global_sso_token' L1
FeatureFlagStore enabled && enabled_for_company L49 / /v1/feature_flags on CUSTOMER_360_URL L77
Config keys CRM_V3_EMBED_URL + CUSTOMER_360_CRM_URL declaredcustom-config.d.ts L20–21
package.json scripts (test, test:coverage, lint, build)

The RFC's own honest caveat — the CRM embed contract/auth/reusability row is not verifiable in this repo — is correct and is the source of REV-1/REV-2/REV-3.


Strengths

  • Verified grounding (Detail 2.0). Every CDP-owned anchor is real and accurately cited — independently re-confirmed against qontak-customer-fe. An agent will not hallucinate the in-repo facts.
  • Bidirectional PRD traceability (Detail 1.A/1.C). All 7 stories + 15 PRD sections mapped; reverse matrix prevents scope creep; cross-squad ACs correctly marked n/a — covered in CRM RFC.
  • Honest blocker disclosure (§5, §7). The RFC refuses to claim readiness it doesn't have: §7 = no, blocking OQs labelled, §2.A flagged provisional. This is exactly the discipline the gate exists to enforce.
  • Safety-first design (D-5, §3, §4.D). Additive, flag-gated (default OFF), instant flag-OFF rollback, associate-existing flow explicitly untouched and regression-guarded.

Biggest Gaps

  • Provisional core contract (REV-3, §2.A). The postMessage payload — the single most important contract for chunks 4–6 — is PRD-sourced, not CRM-frozen. Impact: an agent building chunk 4 today produces code against field names that may change. This is the gate that keeps §7 = no.
  • Unbuilt/blocked dependency (REV-1/REV-2, §1, §5). The embed endpoint is OUT of CRM Phase 1 and in-iframe auth is unconfirmed. Impact: chunks 4–6 have no integration target and may 401 on the create call regardless of CDP correctness.
  • Missing payload-completeness guard (REV-5, §2.2/§3). Origin + version are validated, but a well-origin'd malformed TICKET_CREATED (e.g. no ticketId) flows into fetchWithReset/fallback-associate unchecked. Impact: a runtime error or a fallback POST with undefined ticketId on a partial message.

Priority Actions

  1. §5 OQ-1/OQ-2/OQ-contract (REV-1/2/3) — drive CRM to (a) commit the CDP-reusable embed to a phase, (b) confirm in-iframe auth, (c) freeze the postMessage field names. Nothing in chunks 4–6 is safely executable until these close; this is the §7 flip condition.
  2. §2.2 / §3 Security (REV-5) — add a payload-shape guard (required-field validation per message type) before any side effect; on malformed → no-op + log (treat like TICKET_CREATE_ERROR). Add a Vitest case alongside the spoofed-origin/wrong-version cases already specified.
  3. §5 (REV-5, REV-7) — promote REV-5 and REV-7 into the RFC's §5 Open-Questions table so the RFC stays the canonical unresolved-work surface (the other eight OQs are already there and now id-stamped).
  4. §3 Performance (REV-7) — state the inherited numeric LCP/INP/CLS targets and the concrete browser-version matrix so test assertions have a number, even if "= app default."

Implementation Readiness Checklist

Unblocked (agent can proceed — chunks 1–3)

  • PRD → RFC traceability complete (Detail 1.A/1.C)
  • CDP-owned decisions resolved with alternatives rejected (D-1, D-4, D-5, D-6)
  • Failure modes + error-message catalog (Detail 3.A/3.B) — except malformed-payload (REV-5)
  • Configuration contract (Detail 4.A — flag + 2 config keys, verified)
  • Rollout plan + rollback mechanism (§4, 4.D)
  • Observability metrics + alerts (§3) — naming TBD (REV-6)
  • Task decomposition with per-chunk acceptance criteria (Detail 4.C)
  • CDP-owned interfaces / prop types specified (Detail 2.A)
  • All UI states defined (Detail 2.C)
  • Accessibility specified (Detail 3.C)
  • Performance budget quantified (REV-7 — deferred to app defaults)
  • Browser support matrix explicit (REV-7)

Blocked (must fix first — chunks 4–6)

  • CRM contract frozen (REV-3) — §2.A payload provisional
  • CDP-reusable embed committed to a phase (REV-1) — OUT of CRM Phase 1
  • In-iframe auth confirmed (REV-2) — create call may 401

Verdict: Fix 3 blockers (REV-1/2/3, all CRM-owned) before chunks 4–6. Chunks 1–3 are ready to implement today behind an OFF flag.


Task Manifest

Matches the RFC's Detail 4.C; verified as well-formed and verifiable. Chunks 1–3 unblocked; 4–6 gated on REV-1/2/3.

OrderChunkFiles to Create/ModifyAcceptance CriteriaDependencies
1Scaffold TicketEmbedPanel.vue (iframe + state machine)create features/customers/detail/components/TicketEmbedPanel.vue (+ .spec.ts)renders sandboxed iframe src ending /embed/ticket/create; loading state defaultNone
2Permission + flag gatemodify AssociatedTickets.vue, common/store/FeatureFlagStore.ts; create permission constantentry hidden when perm disabled OR flag OFF; visible iff both (TCKT-S07-NEG)None
3"+" menu + open/close panelmodify AssociatedTickets.vue"Create Ticket" opens panel; back-arrow closes; associate-existing unaffected (TCKT-S01)#1, #2
4Typed postMessage handler + EMBED_INIT sendermodify TicketEmbedPanel.vueEMBED_INIT posted once to new URL(CRM_V3_EMBED_URL).origin, qontakCustomerId === contactId; spoof/wrong-version → no-op; + malformed-payload guard (REV-5)BLOCKED: REV-1/2/3
5Parent success handling (refresh + toast + analytics)modify AssociatedTickets.vuevalid createdfetchTicketsAssociated re-invoked + toast + cdp_ticket_embed_created tracked#4
6Optional fallback associate (OQ-6)modify AssociatedTickets.vuefallback path issues one POST with payload ticketId; failure logs cdp_ticket_embed_associate_failed#5, gated REV-8
7Final verificationpnpm lint · pnpm test:coverage · pnpm build green#1–#6

Dangling Decisions Log

#DecisionLocationOwnerDeadline
None. D-2/D-3 are Partial (provisional interface), not dangling — both have a chosen option; only the consumed contract is unfrozen.Detail 1.B

Open Questions

#QuestionCategorySeverity
1Will CRM commit the CDP-reusable embed to a phase, and when? (REV-1)DEPBlocking
2Does Qontak One SSO/JWT flow into the iframe so the create call authenticates? (REV-2)TDC/DEPBlocking
3What are the frozen EMBED_INIT/TICKET_* field names? (REV-3)CNTBlocking
4Will CRM add embed-web-cdp to ALLOWED_EMBED_SOURCES? (REV-4)DEPImportant
5How is a well-origin'd but malformed message handled? (REV-5)FMCImportant
6Mixpanel event naming — snake_case vs '[Qontak One] [Customer] …'? (REV-6)OBSNice-to-have
7Concrete perf targets + browser matrix, or explicit "= app default" numbers? (REV-7)NFSNice-to-have
8Does the CDP path auto-associate, or is the fallback POST required? (REV-8)TDCImportant
9Figma frames for entry + panel (REV-9)NFS/DesignNice-to-have
10Exact ticket-create permission key (REV-10)CNTImportant

Evidence Notes

  • Detail 2.0 Source Verification — independently re-checked every anchor against the live repo; all accurate. This is what lifts CPA/DEP/SCB to 9.0 and gives High confidence.
  • Detail 2.A UI Contract — full TS interfaces present (CNT strength) but self-flagged provisional (CNT/TDC ceiling). The honesty is correct; the risk is real.
  • §5 + §7 — the RFC's own blocking-OQ discipline drove the HOLD verdict; the review agrees rather than overriding.
  • Mermaid — 4/4 parse headless; the author's mmdc-can't-launch-Chromium note reproduced exactly.

Review History

CycleDateReviewed RFC revision (last_updated / commit)ScoreVerdictFindings open → fixedNotes
R12026-07-012026-06-30 / d656b298.0HOLD (partial-proceed)10 open (3 blocker / 1 major / 6 minor), 0 fixedFirst cycle. Anchors verified against live qontak-customer-fe; 4/4 mermaid parse. REV-5 & REV-7 net-new; rest formalize §5 OQs. Chunks 1–3 executable now; 4–6 blocked on CRM REV-1/2/3.