Merge Main -> Dev#8
Merged
chriskehayias merged 12 commits intodevfrom Apr 18, 2026
Merged
Conversation
…vements Full codebase review: security fixes, testing, and code quality improvements
Add support for MinistryPlatform's record copy and recurrence endpoints:
- POST /tables/{table}/{recordId}/copy
- POST /tables/{table}/{recordId}/copy-record
- GET /tasks/generate-sequence
New types: RecurrencePattern, CopyParameters
New methods: copyRecord, copyRecordWithSubpages, generateSequence
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Field management enhancements: - Expandable field rows: click chevron or field name to reveal inline editing panel with Field Label, Default Value, Filter Clause, Depends On Field, Required/Hidden/Writing Assistant toggles - Schema-enforced required: fields marked IsRequired in the table metadata have their Required switch forced on and disabled with "(schema)" label — cannot be toggled off by the user - Required badge shows on collapsed row for both user-set and schema-enforced required fields - Collapsible groups: click chevron or group name to collapse/expand field list for efficient group reordering - Field lookup changed from useMemo to useState to support mutable field property edits that persist to save payload - updateField function threaded from state hook through editor and group components to field items - Table metadata passed to editor for schema-required field detection Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat(mp): add Copy API and generate-sequence to MPHelper
…ror test
The POST error path in http-client.ts calls `await response.text().catch(() => '')`
to capture the response body for logging. The mock response in the "should throw
error on failed POST request" test only defined `ok`, `status`, and `statusText` —
calling `.text()` on it threw `response.text is not a function` synchronously,
which escaped the `.catch()` handler (it only catches rejected promises, not
sync throws). The mock now stubs `text: () => Promise.resolve('')` so the error
path runs to completion and the assertion sees the expected error message.
Also includes auto-regenerated `_INSTALL/ministryplatform-install.sql` (timestamp
only), `_INSTALL/.sql-hash`, and `next-env.d.ts` (Next.js path update from
`.next/dev/types` to `.next/types`).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
In production users always launch into a specific tool URL
(e.g. /tools/addresslabels?selectionId=123&pageID=456), never
the tool index. Previously, whenever auth redirected them to
/signin, they landed on the tool index (/) after OAuth instead
of the tool they asked for.
Root cause: src/components/layout/auth-wrapper.tsx called
redirect("/signin") with no callbackUrl when the session was
null. This path fires when a stale cookie exists (cookieCache
TTL expired) so the proxy passes through but getSession()
returns null — resulting in the bare /signin redirect and the
signin page defaulting callbackUrl to "/".
Changes:
- src/proxy.ts: forward the original pathname+search via an
x-pathname request header on every pass-through so server
components can reconstruct the callbackUrl.
- src/components/layout/auth-wrapper.tsx: read x-pathname and
redirect to /signin?callbackUrl=<original> instead of bare
/signin.
- src/proxy.test.ts + src/components/layout/auth-wrapper.test.tsx:
new tests covering x-pathname forwarding and callbackUrl
preservation (authenticated, unauthenticated, missing header,
query-string encoding).
Also bundles pre-existing working-tree changes: additional test
coverage across MP services, helper, provider, validation,
barcode-image, field management, address labels, user service,
logger, and http-client; plus reference-doc updates under
.claude/references/ and minor CLAUDE.md/README.md tweaks.
Verification: npm run test:run -> 449/449 pass (35 files).
tsc --noEmit has no errors in touched auth files (pre-existing
errors in helper/provider/logger test files are unrelated).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(dev-panel): scaffold ParamsPanel from tool-params-debug * feat(dev-panel): scaffold SelectionPanel + relocate action test * feat(dev-panel): scaffold ContactRecordsPanel * feat(dev-panel): scaffold UserToolsPanel + relocate action test * test(dev-panel): add failing DevPanel tests (TDD) * feat(dev-panel): implement DevPanel with localhost + dev gate Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(dev-panel): use functional updater in toggle to avoid stale closure * feat(tool): accept optional params prop and render DevPanel * refactor(template-tool): use DevPanel via ToolContainer * refactor(tools): pass params to ToolContainer for DevPanel access * chore: delete legacy debug components and their exports * docs: update references for DevPanel consolidation * docs: remove stale debug-component references from README * docs: fix remaining stale references to deleted debug files * feat(dev-panel): add Deploy Tool control with isolated dev credentials Registers new tools in Ministry Platform directly from the localhost dev panel so devs don't have to hand-run SQL. Uses a separate dev API client so only the developer-only stored procedures use elevated access — production credentials are untouched by every other endpoint. Dev credential pipeline - getClientCredentialsToken accepts a 'default' | 'dev' profile; dev reads MINISTRY_PLATFORM_DEV_CLIENT_ID / _SECRET and throws a clear error when either is missing. - MinistryPlatformClient gains a parallel devToken / devHttpClient with its own cache — the default pipeline is never mutated. - ProcedureService routes procedure calls whose name starts with api_dev_ (case-insensitive, exact underscore boundary) through the dev client for both executeProcedure and executeProcedureWithBody. getProcedures and every other service stay on the default client. Stored procedures (developer-only, granted to DeveloperONLY role) - api_dev_DeployTool — upserts dp_Tools, maps dp_Tool_Pages, grants dp_Role_Tools (Administrators always included). Idempotent; XML-node split for pre-SQL-2016 compat (no STRING_SPLIT). - api_dev_ListPages — searchable dp_Pages picker source (Display_Name, Table_Name search). - api_dev_GetProcedureDefinition — matches the DeveloperONLY role insert pattern used elsewhere (Domain_ID added to the INSERT). UI - DeployToolPanel: collapsible form with Tool Name / Launch Page (prefilled from NEXT_PUBLIC_PROD_URL + pathname) / Description + Additional Data (3-row textareas, 50/50) / four launch flags (default Launch w/ Credentials OFF) / searchable Pages and Roles pickers (Popover + cmdk) with pills; Administrators is auto-selected and locked. Deploy returns the tool row and triggers a UserToolsPanel refresh so the authorization card flips green immediately. - UserToolsPanel cleanup: drops the grid of extraneous paths; shows only the matching green chip when authorized, red warning + Deploy form otherwise. Adds refreshKey + onAuthorizationChange props so the Deploy panel hides once the current tool is authorized (no accidental re-deploy). - Env-var safeguards: amber warning when NEXT_PUBLIC_PROD_URL is unset in UserToolsPanel; getDeployToolEnvStatusAction surfaces missing MINISTRY_PLATFORM_DEV_CLIENT_ID / _SECRET and disables the Deploy button with an amber banner listing the missing vars. Services / actions - ToolService.listPages (SP) / listRoles (dp_Roles via default creds) / deployTool (validates lengths, shapes @PageIDs / @RoleIDs as CSV, booleans to BIT, returns three typed result sets). - Server actions (deploy-tool-actions.ts) gate on session AND NODE_ENV !== 'production' so the deploy path is unreachable from prod builds even if the UI gate were bypassed. Tests: 504 passing (+30). Covers the dev-profile env resolution, parallel token cache isolation, prefix routing (both exec entry points, case variants, api_developer_* false-positive), deploy payload shaping, SP result-set parsing, env-status action, and session/production guards. Also fixes a mockResolvedValueOnce leak in the deploy-tool-actions test by switching to targeted mockReset() per mock. Unrelated drive-by: page-search scroll-to-top fix (page-search.tsx, command.tsx — adds forwarded ref to CommandList). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(tool-service): reuse api_MPNextTools_GetPages for deploy picker api_dev_ListPages overlapped with the existing api_MPNextTools_GetPages SP (same select shape: Page_ID, Display_Name, Table_Name). Dropped the new SP and pointed ToolService.listPages at the established one. - Delete db/api_dev_ListPages.sql; rebuild install script (8 files, 34KB). - ToolService.listPages: calls api_MPNextTools_GetPages (empty params, no @Search on the SP), filters in-memory on Display_Name / Table_Name (case-insensitive), caps at 100 rows. PageLookup gains Table_Name. - Tests updated for the consolidated path: SP name assertion, Display_Name filter, Table_Name filter, whitespace trim, 100-row cap, empty branches. - deploy-tool-actions test mock includes Table_Name. 507/507 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Dependency audit (2026-04-17) — reduces npm audit from 33 → 2 vulns (1 critical, 31 high closed). Only remaining items are xmldom via docxtemplater-image-module-free (no upstream fix). Safe updates (patch/minor, non-breaking): - next 16.2.3 → 16.2.4 - eslint-config-next 16.2.3 → 16.2.4 - better-auth 1.6.2 → 1.6.5 - @react-pdf/renderer 4.4.1 → 4.5.1 - autoprefixer 10.4.27 → 10.5.0 - docxtemplater 3.68.4 → 3.68.5 - postcss 8.5.9 → 8.5.10 - typescript 6.0.2 → 6.0.3 Major upgrade: - mjml 4.18.0 → 5.0.1 (closes 31 high-severity advisories from html-minifier REDoS and mj-include directory traversal). MJML 5 replaces html-minifier with htmlnano. Zero code changes required — the mjml2html signature used by compileMjml() is unchanged, and we already pass minify:false. Client-side editor is unaffected because grapesjs-mjml@1.0.8 pulls mjml-browser@4 as a separate package. Held for later: - eslint 9 → 10 (blocked on eslint-config-next 17) - jsdom 28 → 29 (no security driver) Verification: - npm run build: ok (5s compile, 4s typecheck, Next 16.2.4) - npm run test:run: 507/507 passing - npm run lint: unchanged (95 pre-existing no-explicit-any in tests) End-to-end template-editor compile flow still needs manual smoke test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(context): phase 1 — foundation (schemas, stubs, facts snapshot) Create _meta/ with schemas, conventions, verification-rules, and a frozen facts snapshot at 2026-04-17.md. Add stubs for GLOSSARY, DECISIONS, GOTCHAS, INDEX and the TODO schema. Freeze baseline at SHA 971c40b — test count is 507 across 37 files (spec called out prior README/CLAUDE drift of 241/21). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(context): phase 2 — domain shard docs (17 shards) Generate hierarchical per-domain docs across auth, mp-provider (core + 6 services), mp-schema (migrated from flat files), services (5 app-layer services + query-patterns), components (framework + 6 feature docs), contexts, routing, testing (5 files), dto-constants, and utils. 17 parallel shard agents produced 56 new docs and dropped 38 TODOs for issues discovered. Candidate contributions for GLOSSARY/DECISIONS/GOTCHAS staged at _meta/_phase3-candidates/ for Phase 3 consolidation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(context): phase 3 — cross-cutting layers 6 parallel agents consolidated candidate contributions from Phase 2 into four cross-cutting reference layers plus data-flow: - GLOSSARY.md (52 verified terms, alphabetized) - DECISIONS.md (26 ADRs grouped by domain) - GOTCHAS.md (43 symptom-first traps with TOC) - mp-schema/data-model-map.md (19 hot tables, 18 FK traversals, proc call map) - data-flow/README.md + call-graphs.md (7 key flows with verified file:line traces) - data-flow/error-catalog.md (54 errors by origin layer) Every factual claim verified against source at the frozen baseline SHA. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(context): phase 4 — verification pass + drift fixes + TODO drops 18 parallel verification agents verified every factual claim across 62 docs against source at the frozen baseline SHA. ~1,000 claims checked. ~80 trivial drift fixes applied inline (line numbers, moved paths, broken cross-refs). Most substantial batch: 23 broken 'Related' links in GOTCHAS.md repaired to actual Phase 2 doc filenames. One verification-phase TODO dropped (auth/oauth-flow PKCE reference). No critical flags. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(context): phase 5 — INDEX + CLAUDE.md rewire + cleanup Build reference INDEX.md (navigation map: "for question X, read Y"). Build TODO INDEX.md ranked by severity (14 medium, 21 low, 0 high/critical). Rewire CLAUDE.md links to new subfolder structure. Drift-check .claude/commands/ — fixed two inline (branch-commit model name, pr.md default base branch) and dropped one TODO for stale audit-deps dep list. Delete 7 old flat reference files after grep-sanity confirmed content migration. Remove Phase 1 _brief/ and Phase 3 _phase3-candidates/ temp folders. Final state: - 73 hierarchical reference docs under .claude/references/ - 40 open TODOs (0 critical, 0 high, 14 medium, 21 low + 5 misc low) - README.md bytes unchanged - All 507 tests across 37 files still passing Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * commands and permissions updated --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-safe-updates-mjml5 chore(deps): apply safe updates and upgrade mjml to v5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.