Skip to content

release: v2.1 (reconciled onto release/2.0 base) - #776

Closed
alfredo1996 wants to merge 905 commits into
devfrom
release/2.1
Closed

release: v2.1 (reconciled onto release/2.0 base)#776
alfredo1996 wants to merge 905 commits into
devfrom
release/2.1

Conversation

@alfredo1996

Copy link
Copy Markdown
Owner

Closes #757 epic. Closes #767 (Batch 10 swap).

What this is

The release/2.1 branch was originally cut from main and missed significant refactors that landed on dev and release/2.0. This PR brings the reconciled release/2.1 (now built on top of release/2.0) into dev.

The original release/2.1 is preserved as release/2.1-archived-2026-05-16.

Stacked PRs that built this branch

Batch Issue PR
1 — Bootstrap #758 #768
2 — Env health #759 #769
3 — Migrations (audit, SSO, encryption rotation) #760 #770
4 — Audit logging #761 #771
5 — SSO #762 #772
6 — ENCRYPTION_KEY rotation #763 #773
9 — Docs, CLI integration, agents #766 #775

Plus jest config fix #774 (propagated through the stack).

Excluded from v2.1

Tag

v2.1.0-rc.1 points at the swap commit (a4b519d3).

Verification

Local (top-of-stack a4b519d3):

  • npm run build
  • npm -w app run test — 2586/2586 ✅
  • npm -w component run test — 1259/1259 ✅
  • npm run lint — 4 pre-existing release/2.0 errors (CI doesn't gate on lint)

CI (PR #775, top of stack):

  • TypeScript type-check ✅
  • Unit & Integration Tests ✅
  • Docker Build ✅
  • E2E shards 2/3/4 ✅
  • E2E shards 1/5 — only documented pre-existing flakes (auto-refresh, widget-states refresh button, write-permissions raw-error message)

Reconciliation correctness audit:

  • No conflict markers anywhere
  • 0 file deletions vs release/2.0, 52 added, 31 modified
  • Migration chain integrity: clean (0000→0007, no gaps, no duplicates) — actually fixed a duplicate-id quirk that existed on release/2.0's 0004 snapshot
  • Package boundaries (component/app/, connection/app/) clean
  • 14 files from original release/2.1 not brought over: 12 intentional drops (Batch 7 form wizard, generated docs/.astro, query-editor full-screen feature), 1 missed test restored (chart-renderer.test.tsx), 1 already covered at alternate path (rate-limiter test)

Follow-ups (not blocking this PR)

  • Migration squash to single 0000_initial.sql (no customers yet — see memory)
  • Fix handleRouteError raw-error leak in write-permissions response
  • Stabilize auto-refresh / widget-states refresh-button E2E (pre-existing flakes)

Test plan

🤖 Generated with Claude Code

alfredorubin96 and others added 30 commits April 6, 2026 12:51
Two new documentation pages explaining how to extend NeoBoard:

- developer/extending/new-chart-plugin.mdx — full guide with
  defineChartPlugin() reference, PluginProps table, ECharts vs
  custom patterns, and heatmap example
- developer/extending/new-connector-plugin.mdx — ConnectorPlugin
  reference, ConnectionModule implementation guide, registry API,
  and testing patterns

Updated developer index to link plugin guides prominently.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
docs: chart plugin + connector plugin developer guides
release/1.1 → dev: all v1.1 features + plugin system
1. /dashboards route 404 — add static redirect to / so [id] segment
   doesn't capture "dashboards" as a dashboard ID
2. Theme toggle dead zone — wrap SidebarItem in <button> instead of
   <div> so the entire label area triggers the dropdown
3. Delete dialog shows dashboard name — "Delete X?" instead of generic
4. Create dashboard validation — add required attr + helper text
5. Fullscreen dialog accessibility — replace <h2> with <DialogTitle>
   to fix Radix "DialogContent requires DialogTitle" warning
6. Hide Users nav for non-admin — creator/reader don't see the nav
   item that would just show them a 403

All 1877 tests pass. TypeScript clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: UX audit findings — 6 issues (route, a11y, validation, nav)
- Widget Lab: aria-labels "Edit" → "Edit template", "Delete" → "Delete template" to match E2E selectors
- Graph chart: increase dialog dismiss timeout from 5s → 10s for Radix animation timing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- scripts/setup.sh and setup-local-demo.sh now use docker mode
  (default) instead of --mode local which skips Docker containers
- Health check timeout increased from 60s to 120s — Neo4j cold start
  from empty volumes takes 90-120s
- Health check interval increased from 1s to 2s — less polling noise

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…st health

Root causes of slow/broken setup:
1. start.ts used full=true → built entire Next.js Docker image (minutes)
2. db/migrate.ts used docker exec into neoboard-app (doesn't exist)
3. Neo4j health used cypher-shell (slow JVM startup per poll)
4. Scripts hardcoded --mode local (skipped Docker)
5. Health timeout 60s too short for Neo4j cold start

Fixes:
- start.ts: full=false → docker-compose.yml (DBs only, ~30s)
- db/migrate.ts: always runs locally with DATABASE_URL resolved from
  .env.local (priority) or neoboard.config.json (fallback). Works
  whether DB is Docker, local, or remote.
- docker.ts: isNeo4jReady uses docker inspect (instant) not cypher-shell
- health.ts: timeout 60s→120s, interval 1s→2s
- scripts: removed --mode local (uses docker default)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- start.ts accepts { full } option — full=true uses docker-compose.full.yml
  (app + DBs), full=false uses docker-compose.yml (DBs only)
- demo.ts always passes full=true — users get the complete experience
- setup.ts passes full=false by default — developers start DBs,
  then run the app locally with npm run dev

neoboard demo: ~3.5min → full stack in Docker, seeded, ready
neoboard setup + neoboard dev: ~30s → DBs in Docker, app locally

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…entials

Addresses CodeRabbit review:
- Strip surrounding quotes from DATABASE_URL in .env.local
- URI-encode user/password/database in config fallback URL
- Add tests for both edge cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix 3 ReDoS vulnerabilities (S5852) and suppress 2 CLI false positives:
- widget-lab: remove nested \s* quantifier in copy-name regex
- form-field-validation: exclude dots from domain char class in email regex
- cypher-lang/autocomplete: remove captured star loop (\w)*$ → \w*$
- cli/exec.ts: suppress S4721 + S4036 (hardcoded CLI commands, trusted PATH)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses CodeRabbit review: storybook core was ^10.2.6 while all
@storybook/* addons were already ^10.3.4.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: combined release 1.1 fixes — CLI setup, security hotspots, E2E stability
Move all transform and validate functions from the monolithic
chart-registry.ts into app/src/plugins/transforms/ so each plugin
can import its own transform directly. The chart-registry.ts now
imports from these modules (shim layer) keeping the same public API
for existing consumers (card-container, dashboard-container, etc.).

- 14 transform modules + shared utilities barrel
- All 17 plugins updated to import from ./transforms/ instead of chartRegistry
- 83 new transform unit tests + all 332 existing chart-registry tests pass
- Zero-breaking change: all exports from chart-registry.ts unchanged

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…stry

Add unregister() to ConnectorRegistry interface and implementation for
parity with the chart plugin registry. Add ConnectorFormField interface
and formFields to ConnectorPlugin for auto-generated connection forms.
Update Neo4j and PostgreSQL built-in plugins with form field definitions.
Export new types from the connection package public API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sforms

refactor(plugins): extract chart transforms into standalone modules
…nment

feat(connection): align connector registry API — unregister + formFields
Phase 2: chart-registry.ts is now a thin shim that registers
lightweight plugin entries with pluginRegistry and delegates all
lookups via a Proxy. The static chartRegistry object, getChartConfig,
and all helper functions continue to work unchanged for consumers.

Phase 3: ChartType union is now derived from a single CHART_TYPES
constant in plugins/chart-types.ts. Startup validation in
plugins/index.ts warns if any declared type lacks a registered plugin.

All 1971+ existing tests pass unchanged. New tests verify delegation
behavior and CHART_TYPES/plugin registry alignment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 2: chart-registry.ts is now a thin shim that registers
lightweight plugin entries with pluginRegistry and delegates all
lookups via a Proxy. The static chartRegistry object, getChartConfig,
and all helper functions continue to work unchanged for consumers.

Phase 3: ChartType union is now derived from a single CHART_TYPES
constant in plugins/chart-types.ts. Startup validation in
plugins/index.ts warns if any declared type lacks a registered plugin.

All 1971+ existing tests pass unchanged. New tests verify delegation
behavior and CHART_TYPES/plugin registry alignment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Added settingsSchema field to ChartPluginConfig interface
- Created settings/ directory with Zod schemas for all 17 chart types
- Updated all plugin components to parse settings via schema (no more `as` casts)
- 75 new tests covering defaults, validation, passthrough, and coercion

Closes #420

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…(Phase 5)

Each of the 17 plugins now bundles its chart options via
getChartOptions() from @neoboard/components, replacing scattered
lookups. Adds deprecation comment to the component package's
chart-options index.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… (Phase 7)

Replace all imports from @/lib/chart-registry with @/lib/chart-helpers.
The new module delegates to pluginRegistry and includes lightweight
plugin registration for test environments.

- Create app/src/lib/chart-helpers.ts with helper functions
- Create app/src/lib/__tests__/chart-helpers.test.ts with 21 tests
- Migrate 15 consumer files from chart-registry to chart-helpers
- Delete chart-registry.ts and its 3 test files
- Update test mocks to include getChartOptions for plugin imports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- capture-preview: access isECharts via capabilities object
- card-container: fallback to transform when transformWithMapping undefined
- chart-renderer: accept string type, remove unused ChartType import
- graph plugin: explicit type annotation for onNodeSelect callback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- chart-helpers.test.ts: add next/dynamic and next/navigation mocks (Critical)
- single-value.tsx: use safeParse with fallback for resilience (Major)
- json settings: constrain initialExpanded to non-negative integers (Minor)
- pie settings: constrain topN to non-negative integers (Minor)
- chart-plugin-registry: tighten settingsSchema type to Record<string, unknown> (Minor)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
alfredorubin96 and others added 3 commits May 15, 2026 22:41
Cleans up the lint warning introduced in the previous Batch 9 commit.
The integration test only uses beforeAll for container startup; afterAll
was carried over from a draft and never wired up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure coverage addition — release/2.1 added 3 branch tests for
ChartRenderer (empty data, JsonViewer fallback, MarkdownWidget
fallback). Component code is byte-identical between branches; only
the tests were missing in the reconciled tree.

Found during Batch 10 audit comparing the test-file diff between
top-of-stack and origin/release/2.1.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…gration script

The Batch 9 demo-flow integration test runs full `docker compose up`,
which collides with the postgres service container in the regular
"Unit & Integration Tests" CI job (port 5432 already allocated).

Set SKIP_INTEGRATION=1 in the default `test` and `test:coverage`
scripts so the integration test self-skips (the existing SKIP guard
in demo-flow.test.ts already respects that env var). Add
`test:integration` so the dedicated cli-integration.yml workflow
can opt back in (the workflow already references this script name).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 273 files, which is 123 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 50f768e7-bd29-405f-b286-b1ac11589196

📥 Commits

Reviewing files that changed from the base of the PR and between eaca140 and 9a58038.

⛔ Files ignored due to path filters (27)
  • app/.screenshots/after/api-keys-create-dialog.png is excluded by !**/*.png, !app/.screenshots/**
  • app/.screenshots/after/api-keys-populated-table.png is excluded by !**/*.png, !app/.screenshots/**
  • app/.screenshots/before/api-keys-create-dialog.png is excluded by !**/*.png, !app/.screenshots/**
  • app/.screenshots/before/api-keys-created-dialog.png is excluded by !**/*.png, !app/.screenshots/**
  • app/.screenshots/before/api-keys-empty-state.png is excluded by !**/*.png, !app/.screenshots/**
  • app/.screenshots/before/api-keys-populated-table.png is excluded by !**/*.png, !app/.screenshots/**
  • app/.screenshots/before/api-keys-revoke-confirm.png is excluded by !**/*.png, !app/.screenshots/**
  • app/.screenshots/form-widget-403-write-permission.png is excluded by !**/*.png, !app/.screenshots/**
  • app/drizzle/migrations/0000_wooden_zeigeist.sql is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/0001_rapid_iron_monger.sql is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/0002_redundant_night_nurse.sql is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/0003_loving_centennial.sql is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/0004_furry_scourge.sql is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/0005_perfect_paibok.sql is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/0006_busy_champions.sql is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/0007_free_loners.sql is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/meta/0000_snapshot.json is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/meta/0001_snapshot.json is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/meta/0002_snapshot.json is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/meta/0003_snapshot.json is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/meta/0004_snapshot.json is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/meta/0005_snapshot.json is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/meta/0006_snapshot.json is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/meta/0007_snapshot.json is excluded by !app/drizzle/migrations/**
  • app/drizzle/migrations/meta/_journal.json is excluded by !app/drizzle/migrations/**
  • app/public/logo.svg is excluded by !**/*.svg
  • app/public/og-image.svg is excluded by !**/*.svg
📒 Files selected for processing (273)
  • .claude/.gitignore
  • .claude/agents/code-reviewer.md
  • .claude/agents/feature-reviewer.md
  • .claude/agents/lint-fix.md
  • .claude/agents/project-architect.md
  • .claude/agents/test-runner.md
  • .claude/agents/user-sim-admin.md
  • .claude/agents/user-sim-creator.md
  • .claude/agents/ux-crawler.md
  • .claude/hooks/check-boundaries.sh
  • .claude/hooks/check-coverage.sh
  • .claude/hooks/check-credential-logging.sh
  • .claude/hooks/check-migration-guard.sh
  • .claude/hooks/check-query-safety.sh
  • .claude/hooks/enforce-e2e.sh
  • .claude/hooks/format-and-lint.sh
  • .claude/hooks/session-context.sh
  • .claude/settings.json
  • .claude/skills/code/SKILL.md
  • .claude/skills/commit/SKILL.md
  • .claude/skills/components/SKILL.md
  • .claude/skills/design-review/skill.md
  • .claude/skills/drill/SKILL.md
  • .claude/skills/fix-pr-reviews/SKILL.md
  • .claude/skills/github-workflow/SKILL.md
  • .claude/skills/harden/SKILL.md
  • .claude/skills/issue/SKILL.md
  • .claude/skills/next/SKILL.md
  • .claude/skills/plan/SKILL.md
  • .claude/skills/pr/SKILL.md
  • .claude/skills/prioritize/SKILL.md
  • .claude/skills/release-plan/SKILL.md
  • .claude/skills/review/SKILL.md
  • .claude/skills/test/SKILL.md
  • .coderabbit.yaml
  • .dockerignore
  • .editorconfig
  • .env.example
  • .github/CODE_OF_CONDUCT.md
  • .github/CONTRIBUTING.md
  • .github/ISSUE_TEMPLATE/bug-report.yml
  • .github/ISSUE_TEMPLATE/config.yml
  • .github/ISSUE_TEMPLATE/feature-request.yml
  • .github/PULL_REQUEST_TEMPLATE.md
  • .github/SECURITY.md
  • .github/dependabot.yml
  • .github/workflows/ci.yml
  • .github/workflows/cli-integration.yml
  • .github/workflows/connection-tests.yml
  • .github/workflows/release.yml
  • .gitignore
  • .gitmodules
  • .husky/pre-commit
  • .mcp.json
  • .nvmrc
  • ARCHITECTURE.md
  • CHANGELOG.md
  • CLAUDE.md
  • DEVELOPMENT.md
  • Dockerfile
  • LICENSE
  • PLUGINS.md
  • README.md
  • app/.env.example
  • app/drizzle.config.ts
  • app/e2e/api-docs.spec.ts
  • app/e2e/api-keys.spec.ts
  • app/e2e/auth-states.spec.ts
  • app/e2e/auth.spec.ts
  • app/e2e/auto-refresh.spec.ts
  • app/e2e/charts.spec.ts
  • app/e2e/code-completion.spec.ts
  • app/e2e/connection-advanced.spec.ts
  • app/e2e/connections.spec.ts
  • app/e2e/content-widgets.spec.ts
  • app/e2e/dashboard-metadata.spec.ts
  • app/e2e/dashboard-portability.spec.ts
  • app/e2e/dashboard-states.spec.ts
  • app/e2e/dashboard-visibility.spec.ts
  • app/e2e/dashboards.spec.ts
  • app/e2e/design-system.spec.ts
  • app/e2e/empty-states.spec.ts
  • app/e2e/fixtures.ts
  • app/e2e/fixtures/imports/malformed.txt
  • app/e2e/fixtures/imports/missing-fields.json
  • app/e2e/fixtures/imports/neodash-sample.json
  • app/e2e/fixtures/imports/two-connections.json
  • app/e2e/form-widget.spec.ts
  • app/e2e/global-setup.ts
  • app/e2e/global-teardown.ts
  • app/e2e/grid.spec.ts
  • app/e2e/heavy-widgets.spec.ts
  • app/e2e/import-validation.spec.ts
  • app/e2e/navigation.spec.ts
  • app/e2e/new-charts.spec.ts
  • app/e2e/pages/auth.ts
  • app/e2e/pages/sidebar.ts
  • app/e2e/parameter-types.spec.ts
  • app/e2e/parameters.spec.ts
  • app/e2e/performance.spec.ts
  • app/e2e/query-safety.spec.ts
  • app/e2e/responsive.spec.ts
  • app/e2e/settings-profile.spec.ts
  • app/e2e/sharing-permissions.spec.ts
  • app/e2e/sidebar-states.spec.ts
  • app/e2e/styling-rules.spec.ts
  • app/e2e/theme.spec.ts
  • app/e2e/transforms.spec.ts
  • app/e2e/users.spec.ts
  • app/e2e/widget-lab.spec.ts
  • app/e2e/widget-states.spec.ts
  • app/e2e/widgets.spec.ts
  • app/e2e/write-permissions.spec.ts
  • app/next-env.d.ts
  • app/next.config.ts
  • app/package.json
  • app/playwright.config.ts
  • app/postcss.config.js
  • app/public/site.webmanifest
  • app/scripts/lint-migrations.mjs
  • app/src/__tests__/helpers/drizzle-mocks.ts
  • app/src/__tests__/helpers/next-mocks.ts
  • app/src/__tests__/helpers/request-helpers.ts
  • app/src/__tests__/instrumentation.test.ts
  • app/src/__tests__/proxy.test.ts
  • app/src/__tests__/security-headers.test.ts
  • app/src/app/(auth)/change-password/page.tsx
  • app/src/app/(auth)/login/__tests__/page.test.tsx
  • app/src/app/(auth)/login/page.tsx
  • app/src/app/(auth)/signup/__tests__/page.test.tsx
  • app/src/app/(auth)/signup/page.tsx
  • app/src/app/(dashboard)/[id]/edit/page.tsx
  • app/src/app/(dashboard)/[id]/page.tsx
  • app/src/app/(dashboard)/__tests__/layout.test.tsx
  • app/src/app/(dashboard)/connections/page.tsx
  • app/src/app/(dashboard)/dashboards/page.tsx
  • app/src/app/(dashboard)/layout.tsx
  • app/src/app/(dashboard)/page.tsx
  • app/src/app/(dashboard)/settings/__tests__/page.test.ts
  • app/src/app/(dashboard)/settings/api-keys/page.tsx
  • app/src/app/(dashboard)/settings/authentication/__tests__/page.test.tsx
  • app/src/app/(dashboard)/settings/authentication/page.tsx
  • app/src/app/(dashboard)/settings/layout.tsx
  • app/src/app/(dashboard)/settings/page.tsx
  • app/src/app/(dashboard)/settings/profile/page.tsx
  • app/src/app/(dashboard)/users/page.tsx
  • app/src/app/(dashboard)/widget-lab/page.tsx
  • app/src/app/api/admin/rotate-key/__tests__/route.test.ts
  • app/src/app/api/admin/rotate-key/route.ts
  • app/src/app/api/audit-logs/__tests__/route.test.ts
  • app/src/app/api/audit-logs/route.ts
  • app/src/app/api/auth/[...nextauth]/route.ts
  • app/src/app/api/auth/bootstrap-status/__tests__/route.test.ts
  • app/src/app/api/auth/bootstrap-status/route.ts
  • app/src/app/api/auth/sso-providers/__tests__/route.test.ts
  • app/src/app/api/auth/sso-providers/route.ts
  • app/src/app/api/connections/[id]/__tests__/route.test.ts
  • app/src/app/api/connections/[id]/databases/__tests__/route.test.ts
  • app/src/app/api/connections/[id]/databases/route.ts
  • app/src/app/api/connections/[id]/reassign/__tests__/route.test.ts
  • app/src/app/api/connections/[id]/reassign/route.ts
  • app/src/app/api/connections/[id]/route.ts
  • app/src/app/api/connections/[id]/schema/__tests__/route.test.ts
  • app/src/app/api/connections/[id]/schema/route.ts
  • app/src/app/api/connections/[id]/test/__tests__/route.test.ts
  • app/src/app/api/connections/[id]/test/route.ts
  • app/src/app/api/connections/[id]/usage/__tests__/route.test.ts
  • app/src/app/api/connections/[id]/usage/route.ts
  • app/src/app/api/connections/__tests__/route.test.ts
  • app/src/app/api/connections/list-databases-inline/__tests__/route.test.ts
  • app/src/app/api/connections/list-databases-inline/route.ts
  • app/src/app/api/connections/route.ts
  • app/src/app/api/connections/test-inline/__tests__/route.test.ts
  • app/src/app/api/connections/test-inline/route.ts
  • app/src/app/api/dashboards/[id]/__tests__/route.test.ts
  • app/src/app/api/dashboards/[id]/duplicate/__tests__/route.test.ts
  • app/src/app/api/dashboards/[id]/duplicate/route.ts
  • app/src/app/api/dashboards/[id]/export/__tests__/route.test.ts
  • app/src/app/api/dashboards/[id]/export/route.ts
  • app/src/app/api/dashboards/[id]/route.ts
  • app/src/app/api/dashboards/[id]/share/__tests__/route.test.ts
  • app/src/app/api/dashboards/[id]/share/route.ts
  • app/src/app/api/dashboards/__tests__/route.test.ts
  • app/src/app/api/dashboards/import/__tests__/route.test.ts
  • app/src/app/api/dashboards/import/route.ts
  • app/src/app/api/dashboards/route.ts
  • app/src/app/api/docs/__tests__/route.test.ts
  • app/src/app/api/docs/route.ts
  • app/src/app/api/features/__tests__/route.test.ts
  • app/src/app/api/features/route.ts
  • app/src/app/api/health/__tests__/route.test.ts
  • app/src/app/api/health/route.ts
  • app/src/app/api/keys/[id]/__tests__/route.test.ts
  • app/src/app/api/keys/[id]/route.ts
  • app/src/app/api/keys/__tests__/route.test.ts
  • app/src/app/api/keys/route.ts
  • app/src/app/api/openapi.json/__tests__/route.test.ts
  • app/src/app/api/openapi.json/route.ts
  • app/src/app/api/openapi/__tests__/route.test.ts
  • app/src/app/api/openapi/route.ts
  • app/src/app/api/query/__tests__/route.test.ts
  • app/src/app/api/query/route.ts
  • app/src/app/api/query/write/__tests__/route.test.ts
  • app/src/app/api/query/write/route.ts
  • app/src/app/api/sso-providers/__tests__/route.test.ts
  • app/src/app/api/sso-providers/route.ts
  • app/src/app/api/users/[id]/__tests__/route.test.ts
  • app/src/app/api/users/[id]/reset-password/__tests__/route.test.ts
  • app/src/app/api/users/[id]/reset-password/route.ts
  • app/src/app/api/users/[id]/route.ts
  • app/src/app/api/users/__tests__/route.test.ts
  • app/src/app/api/users/me/__tests__/route.test.ts
  • app/src/app/api/users/me/password/__tests__/route.test.ts
  • app/src/app/api/users/me/password/route.ts
  • app/src/app/api/users/me/route.ts
  • app/src/app/api/users/route.ts
  • app/src/app/api/widget-templates/[id]/__tests__/route.test.ts
  • app/src/app/api/widget-templates/[id]/route.ts
  • app/src/app/api/widget-templates/__tests__/route.test.ts
  • app/src/app/api/widget-templates/route.ts
  • app/src/app/api/widget-templates/shared.ts
  • app/src/app/error.tsx
  • app/src/app/global-error.tsx
  • app/src/app/globals.css
  • app/src/app/layout.tsx
  • app/src/components/__tests__/card-container-states.test.tsx
  • app/src/components/__tests__/card-container.test.tsx
  • app/src/components/__tests__/chart-error-boundary-unit.test.tsx
  • app/src/components/__tests__/chart-error-boundary.test.tsx
  • app/src/components/__tests__/chart-renderer.test.tsx
  • app/src/components/__tests__/dashboard-container-branches.test.tsx
  • app/src/components/__tests__/dashboard-container-dblclick.test.tsx
  • app/src/components/__tests__/dashboard-error-boundary.test.tsx
  • app/src/components/__tests__/form-widget-renderer-fields.test.tsx
  • app/src/components/__tests__/form-widget-renderer-readonly.test.tsx
  • app/src/components/__tests__/form-widget-renderer.test.ts
  • app/src/components/__tests__/format-parameter-value.test.ts
  • app/src/components/__tests__/widget-outdated.test.ts
  • app/src/components/card-container.tsx
  • app/src/components/chart-error-boundary.tsx
  • app/src/components/chart-renderer.tsx
  • app/src/components/dashboard-assign-panel.tsx
  • app/src/components/dashboard-container.tsx
  • app/src/components/dashboard-error-boundary.tsx
  • app/src/components/dashboard-picker-dialog.tsx
  • app/src/components/db-logos.tsx
  • app/src/components/debounced-text-input.tsx
  • app/src/components/form-widget-renderer.tsx
  • app/src/components/graph-exploration-wrapper.tsx
  • app/src/components/page-tabs.tsx
  • app/src/components/parameter-widget-renderer.tsx
  • app/src/components/parameters/__tests__/debounce-logic.test.ts
  • app/src/components/parameters/__tests__/param-cascading-select.test.ts
  • app/src/components/parameters/__tests__/param-date-range.test.ts
  • app/src/components/parameters/__tests__/param-date-relative.test.ts
  • app/src/components/parameters/__tests__/param-date.test.ts
  • app/src/components/parameters/__tests__/param-multi-select.test.ts
  • app/src/components/parameters/__tests__/param-number-range.test.ts
  • app/src/components/parameters/__tests__/param-select.test.ts
  • app/src/components/parameters/__tests__/param-text.test.ts
  • app/src/components/parameters/__tests__/seed-query-logic.test.ts
  • app/src/components/parameters/__tests__/use-cascading-clear.test.ts
  • app/src/components/parameters/__tests__/use-param-actions.test.ts
  • app/src/components/parameters/index.ts
  • app/src/components/parameters/param-cascading-select.tsx
  • app/src/components/parameters/param-date-range.tsx
  • app/src/components/parameters/param-date-relative.tsx
  • app/src/components/parameters/param-date.tsx
  • app/src/components/parameters/param-multi-select.tsx
  • app/src/components/parameters/param-number-range.tsx
  • app/src/components/parameters/param-select.tsx
  • app/src/components/parameters/param-text.tsx
  • app/src/components/parameters/use-cascading-clear.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/2.1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776:

#779 — Refresh button silently no-op'd
  dashboard-container.tsx invalidated TanStack Query with a 4-element key
  (["widget-query", connectionId, query, params]) but useWidgetQuery's
  actual key is 6 elements
  (["widget-query", connectionId, database, query, params, staleTime]).
  Position 2 mismatched (query string vs null/database) so the prefix
  match failed and no refetch ever fired. Fixed in:
    e2e/auto-refresh.spec.ts:107  manual per-widget refresh re-fetch
    e2e/auto-refresh.spec.ts:221  manual refresh, auto-refresh disabled
    e2e/widget-states.spec.ts:222 showRefreshButton re-fetches
    e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh
  Fix: align invalidation prefix to match through `query` slot. Stop at
  `query` because params/staleTime are merged at hook call time and not
  reproducible at refresh time.

#778 — Write route leaked raw driver error
  handleRouteError -> sanitizeErrorMessage was deliberately permissive
  (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax
  errors echoed user SQL into the response body. Fixed in:
    e2e/write-permissions.spec.ts:255 "safe 500 message" assertion
      expected "Write query execution failed", got 'syntax error at or
      near "THIS"'.
  Fix: opt-in `safeMessage` flag on handleRouteError that collapses
  untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise)
  still get specific handling. Used by /api/query/write only — read
  routes preserve current behavior so users can debug their own queries.

Tests:
  - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass)
  - write/route.test.ts: updated leaky-behavior assertion to verify the
    sanitized message + negative match against /syntax error/
  - dashboard-container tests: 27/27 still pass
  - E2E: all 5 originally-failing tests now pass locally (20/20)
alfredo1996 pushed a commit that referenced this pull request May 15, 2026
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776:

#779 — Refresh button silently no-op'd
  dashboard-container.tsx invalidated TanStack Query with a 4-element key
  (["widget-query", connectionId, query, params]) but useWidgetQuery's
  actual key is 6 elements
  (["widget-query", connectionId, database, query, params, staleTime]).
  Position 2 mismatched (query string vs null/database) so the prefix
  match failed and no refetch ever fired. Fixed in:
    e2e/auto-refresh.spec.ts:107  manual per-widget refresh re-fetch
    e2e/auto-refresh.spec.ts:221  manual refresh, auto-refresh disabled
    e2e/widget-states.spec.ts:222 showRefreshButton re-fetches
    e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh
  Fix: align invalidation prefix to match through `query` slot. Stop at
  `query` because params/staleTime are merged at hook call time and not
  reproducible at refresh time.

#778 — Write route leaked raw driver error
  handleRouteError -> sanitizeErrorMessage was deliberately permissive
  (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax
  errors echoed user SQL into the response body. Fixed in:
    e2e/write-permissions.spec.ts:255 "safe 500 message" assertion
      expected "Write query execution failed", got 'syntax error at or
      near "THIS"'.
  Fix: opt-in `safeMessage` flag on handleRouteError that collapses
  untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise)
  still get specific handling. Used by /api/query/write only — read
  routes preserve current behavior so users can debug their own queries.

Tests:
  - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass)
  - write/route.test.ts: updated leaky-behavior assertion to verify the
    sanitized message + negative match against /syntax error/
  - dashboard-container tests: 27/27 still pass
  - E2E: all 5 originally-failing tests now pass locally (20/20)
alfredo1996 pushed a commit that referenced this pull request May 15, 2026
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776:

#779 — Refresh button silently no-op'd
  dashboard-container.tsx invalidated TanStack Query with a 4-element key
  (["widget-query", connectionId, query, params]) but useWidgetQuery's
  actual key is 6 elements
  (["widget-query", connectionId, database, query, params, staleTime]).
  Position 2 mismatched (query string vs null/database) so the prefix
  match failed and no refetch ever fired. Fixed in:
    e2e/auto-refresh.spec.ts:107  manual per-widget refresh re-fetch
    e2e/auto-refresh.spec.ts:221  manual refresh, auto-refresh disabled
    e2e/widget-states.spec.ts:222 showRefreshButton re-fetches
    e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh
  Fix: align invalidation prefix to match through `query` slot. Stop at
  `query` because params/staleTime are merged at hook call time and not
  reproducible at refresh time.

#778 — Write route leaked raw driver error
  handleRouteError -> sanitizeErrorMessage was deliberately permissive
  (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax
  errors echoed user SQL into the response body. Fixed in:
    e2e/write-permissions.spec.ts:255 "safe 500 message" assertion
      expected "Write query execution failed", got 'syntax error at or
      near "THIS"'.
  Fix: opt-in `safeMessage` flag on handleRouteError that collapses
  untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise)
  still get specific handling. Used by /api/query/write only — read
  routes preserve current behavior so users can debug their own queries.

Tests:
  - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass)
  - write/route.test.ts: updated leaky-behavior assertion to verify the
    sanitized message + negative match against /syntax error/
  - dashboard-container tests: 27/27 still pass
  - E2E: all 5 originally-failing tests now pass locally (20/20)
alfredo1996 pushed a commit that referenced this pull request May 15, 2026
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776:

#779 — Refresh button silently no-op'd
  dashboard-container.tsx invalidated TanStack Query with a 4-element key
  (["widget-query", connectionId, query, params]) but useWidgetQuery's
  actual key is 6 elements
  (["widget-query", connectionId, database, query, params, staleTime]).
  Position 2 mismatched (query string vs null/database) so the prefix
  match failed and no refetch ever fired. Fixed in:
    e2e/auto-refresh.spec.ts:107  manual per-widget refresh re-fetch
    e2e/auto-refresh.spec.ts:221  manual refresh, auto-refresh disabled
    e2e/widget-states.spec.ts:222 showRefreshButton re-fetches
    e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh
  Fix: align invalidation prefix to match through `query` slot. Stop at
  `query` because params/staleTime are merged at hook call time and not
  reproducible at refresh time.

#778 — Write route leaked raw driver error
  handleRouteError -> sanitizeErrorMessage was deliberately permissive
  (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax
  errors echoed user SQL into the response body. Fixed in:
    e2e/write-permissions.spec.ts:255 "safe 500 message" assertion
      expected "Write query execution failed", got 'syntax error at or
      near "THIS"'.
  Fix: opt-in `safeMessage` flag on handleRouteError that collapses
  untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise)
  still get specific handling. Used by /api/query/write only — read
  routes preserve current behavior so users can debug their own queries.

Tests:
  - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass)
  - write/route.test.ts: updated leaky-behavior assertion to verify the
    sanitized message + negative match against /syntax error/
  - dashboard-container tests: 27/27 still pass
  - E2E: all 5 originally-failing tests now pass locally (20/20)
alfredo1996 pushed a commit that referenced this pull request May 15, 2026
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776:

#779 — Refresh button silently no-op'd
  dashboard-container.tsx invalidated TanStack Query with a 4-element key
  (["widget-query", connectionId, query, params]) but useWidgetQuery's
  actual key is 6 elements
  (["widget-query", connectionId, database, query, params, staleTime]).
  Position 2 mismatched (query string vs null/database) so the prefix
  match failed and no refetch ever fired. Fixed in:
    e2e/auto-refresh.spec.ts:107  manual per-widget refresh re-fetch
    e2e/auto-refresh.spec.ts:221  manual refresh, auto-refresh disabled
    e2e/widget-states.spec.ts:222 showRefreshButton re-fetches
    e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh
  Fix: align invalidation prefix to match through `query` slot. Stop at
  `query` because params/staleTime are merged at hook call time and not
  reproducible at refresh time.

#778 — Write route leaked raw driver error
  handleRouteError -> sanitizeErrorMessage was deliberately permissive
  (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax
  errors echoed user SQL into the response body. Fixed in:
    e2e/write-permissions.spec.ts:255 "safe 500 message" assertion
      expected "Write query execution failed", got 'syntax error at or
      near "THIS"'.
  Fix: opt-in `safeMessage` flag on handleRouteError that collapses
  untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise)
  still get specific handling. Used by /api/query/write only — read
  routes preserve current behavior so users can debug their own queries.

Tests:
  - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass)
  - write/route.test.ts: updated leaky-behavior assertion to verify the
    sanitized message + negative match against /syntax error/
  - dashboard-container tests: 27/27 still pass
  - E2E: all 5 originally-failing tests now pass locally (20/20)
alfredo1996 pushed a commit that referenced this pull request May 15, 2026
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776:

#779 — Refresh button silently no-op'd
  dashboard-container.tsx invalidated TanStack Query with a 4-element key
  (["widget-query", connectionId, query, params]) but useWidgetQuery's
  actual key is 6 elements
  (["widget-query", connectionId, database, query, params, staleTime]).
  Position 2 mismatched (query string vs null/database) so the prefix
  match failed and no refetch ever fired. Fixed in:
    e2e/auto-refresh.spec.ts:107  manual per-widget refresh re-fetch
    e2e/auto-refresh.spec.ts:221  manual refresh, auto-refresh disabled
    e2e/widget-states.spec.ts:222 showRefreshButton re-fetches
    e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh
  Fix: align invalidation prefix to match through `query` slot. Stop at
  `query` because params/staleTime are merged at hook call time and not
  reproducible at refresh time.

#778 — Write route leaked raw driver error
  handleRouteError -> sanitizeErrorMessage was deliberately permissive
  (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax
  errors echoed user SQL into the response body. Fixed in:
    e2e/write-permissions.spec.ts:255 "safe 500 message" assertion
      expected "Write query execution failed", got 'syntax error at or
      near "THIS"'.
  Fix: opt-in `safeMessage` flag on handleRouteError that collapses
  untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise)
  still get specific handling. Used by /api/query/write only — read
  routes preserve current behavior so users can debug their own queries.

Tests:
  - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass)
  - write/route.test.ts: updated leaky-behavior assertion to verify the
    sanitized message + negative match against /syntax error/
  - dashboard-container tests: 27/27 still pass
  - E2E: all 5 originally-failing tests now pass locally (20/20)
alfredo1996 pushed a commit that referenced this pull request May 15, 2026
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776:

#779 — Refresh button silently no-op'd
  dashboard-container.tsx invalidated TanStack Query with a 4-element key
  (["widget-query", connectionId, query, params]) but useWidgetQuery's
  actual key is 6 elements
  (["widget-query", connectionId, database, query, params, staleTime]).
  Position 2 mismatched (query string vs null/database) so the prefix
  match failed and no refetch ever fired. Fixed in:
    e2e/auto-refresh.spec.ts:107  manual per-widget refresh re-fetch
    e2e/auto-refresh.spec.ts:221  manual refresh, auto-refresh disabled
    e2e/widget-states.spec.ts:222 showRefreshButton re-fetches
    e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh
  Fix: align invalidation prefix to match through `query` slot. Stop at
  `query` because params/staleTime are merged at hook call time and not
  reproducible at refresh time.

#778 — Write route leaked raw driver error
  handleRouteError -> sanitizeErrorMessage was deliberately permissive
  (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax
  errors echoed user SQL into the response body. Fixed in:
    e2e/write-permissions.spec.ts:255 "safe 500 message" assertion
      expected "Write query execution failed", got 'syntax error at or
      near "THIS"'.
  Fix: opt-in `safeMessage` flag on handleRouteError that collapses
  untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise)
  still get specific handling. Used by /api/query/write only — read
  routes preserve current behavior so users can debug their own queries.

Tests:
  - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass)
  - write/route.test.ts: updated leaky-behavior assertion to verify the
    sanitized message + negative match against /syntax error/
  - dashboard-container tests: 27/27 still pass
  - E2E: all 5 originally-failing tests now pass locally (20/20)
alfredorubin96 and others added 5 commits May 16, 2026 02:01
SonarCloud flagged 2 MINOR code smells on PR #771's audit-logs route:
the global `parseInt` shadows ES2015's namespaced `Number.parseInt`.
4-min effort total. Same behavior, eslint-friendly, satisfies the
"prefer namespaced parse functions" convention.
… name races

Root cause of repeated "strict mode violation: getByText('Neo4j Bar Template',
{ exact: true }) resolved to 2 elements" failures on shard 5 across multiple
PRs (#770, #771): the consumption describe block creates two templates with
hardcoded names ("Neo4j Bar Template", "PostgreSQL Table Template") in
beforeEach. With fullyParallel=true and 2 CI workers, two of these tests'
beforeEach hooks race — both succeed in POSTing — leaving 2 elements with
the same text in the DOM and breaking strict-mode locators.

Fix: declare test.describe.configure({ mode: "serial" }) on the consumption
describe so its tests run sequentially within a worker. Each test's
beforeEach/afterEach now owns the shared template names exclusively.

Verified locally: all 4 consumption tests pass with --workers=2.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR #768 unit suite failed with "Test timed out in 5000ms" on
"shows selection count text when rows are selected with pagination active"
in data-grid-dynamic-pagination.test.tsx:349.

Same root cause as #439 (commit 0ff3419): under coverage instrumentation
in CI, rendering 30 rows + userEvent.click + selection state propagation
exceeds the default 5s budget. The previous test in the same describe
("can select all rows on the current page") was already bumped to 15000ms
for the same reason — this sibling test was missed in that PR.

Match the precedent so both selection-related tests have headroom.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The deferred-ready setTimeout in DashboardContainer.openFullscreen could
fire after the component unmounted, calling setState on a torn-down tree.
In CI (vitest jsdom + coverage) this surfaced as an unhandled
"window is not defined" exception originating from
dashboard-container-branches.test.tsx, failing the run despite all 2592
tests passing.

Track the timer in a ref and clear it on unmount, on close, and when
re-arming via openFullscreen. Production behavior unchanged; defensive
cleanup prevents the React unmounted-update warning in browsers too.
Add tests for the close, re-arm, and unmount paths of the fullscreen
ready-timer ref so SonarCloud's new-coverage check on the prior fix
clears the 80% threshold (was 75% on 4 uncovered lines).

- close-while-pending → exercises closeFullscreen clearTimeout branch
- re-arm openFullscreen → exercises previous-ref clearTimeout branch
- unmount-while-pending → exercises useEffect cleanup branch

Dialog mock now exposes onOpenChange via a close button so the close
path is reachable from tests; vi.useFakeTimers lets us assert the
timer was cleared (no setState fires on a torn-down tree).
@alfredo1996

Copy link
Copy Markdown
Owner Author

Superseded — switching to per-batch re-implementation on current dev.

The release/2.0 cascade (PRs #768#775) merged successfully, so release/2.0 and release/2.1 now contain identical content (the full v2.1 payload). However, merging that payload into dev would surface 202 file conflicts in a single unreviewable mega-PR — both sides made substantive changes to the same hot files (dashboard-container.tsx, api/query/write, form-widget-renderer.tsx, hooks, etc.) and dev has its own real feature work since the v2.1 branch point (form wizard #165, markdown syntax highlighting #166, percent-stacked bar #167, SVG export #706, HTML-escape security fix in chart tooltips, dozens of test stabilizations).

New plan: re-implement each v2.1 batch as a clean PR against current dev, using release/2.0 as code reference. Smaller PRs, reviewable diffs, no hidden conflict-resolution bugs.

Branches kept as read-only reference:

  • release/2.0 — pristine post-cascade snapshot of the v2.1 payload
  • release/2.1 — same content, with the iterative stabilization commits on top

They will be deleted once all v2.1 batches have landed cleanly on dev.

Re-implementation order (smallest first to validate the workflow):

  1. fix(api): handleRouteError leaks raw SQL/driver error message via fallback #778 — refresh-button no-op fix
  2. test(e2e): stabilize refresh-button flakes (auto-refresh + widget-states + widget-lab) #779 — write-route raw error leak
  3. Batch 1: Bootstrap reconciled branch (env, gitmodules, enterprise submodule, hooks) #758 — bootstrap (likely no-op if dev already has it)
  4. Batch 2: Env config validation + security headers + health endpoint upgrade #759 — env config + security headers + health endpoint
  5. Batch 4: Audit logging port #761 — audit logging + password change (depends on Batch 2: Env config validation + security headers + health endpoint upgrade #759)
  6. Batch 5: SSO / OIDC providers port #762 — SSO/OIDC (depends on Batch 2: Env config validation + security headers + health endpoint upgrade #759)
  7. Batch 6: Encryption key rotation port #763 — ENCRYPTION_KEY rotation (depends on Batch 2: Env config validation + security headers + health endpoint upgrade #759)
  8. Batch 7: Form wizard port (HIGH RISK — adapt to 2.0 modular widget editor) #764, Batch 8: Component utilities (markdown highlighter, query snippets, extensions) #765 — to be re-scoped against current dev
  9. Batch 9: Docs + CLI integration test + agent/skill updates #766 — docs + CLI integration + agent updates (last)

Each batch will go through /drill then full TDD on dev with reference reads from release/2.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Batch 10: Branch swap + full E2E verification EPIC: Reconcile release/2.1 onto release/2.0 base (branch swap)

2 participants