Skip to content

feat(worker): Phase 3b — port domain writes (warranties/insurance/legal-cases creates)#40

Open
chitcommit wants to merge 1 commit into
feat/hono-phase-3a-asset-writesfrom
feat/hono-phase-3b-domain-writes
Open

feat(worker): Phase 3b — port domain writes (warranties/insurance/legal-cases creates)#40
chitcommit wants to merge 1 commit into
feat/hono-phase-3a-asset-writesfrom
feat/hono-phase-3b-domain-writes

Conversation

@chitcommit
Copy link
Copy Markdown
Contributor

Summary

Ports the three remaining domain write routes from Express to Hono:

  • POST /api/assets/:assetId/warrantiesserver/routes.ts:476
  • POST /api/assets/:assetId/insuranceserver/routes.ts:508
  • POST /api/legal-casesserver/routes.ts:540

Stacks on #39#38#37#36#34#33. Base: feat/hono-phase-3a-asset-writes.

Pattern

Mirrors Phase 3a evidence attach:

  • Zod input schemas omit server-owned fields (userId, assetId from URL, chittyId) so clients cannot spoof them.
  • For warranties + insurance, parent-asset ownership is verified inside the same DB transaction as the INSERT (SELECT id FROM assets WHERE id=? AND user_id=?) → 404 on mismatch with no existence leak.
  • For legal_cases, user_id is server-injected from claims; no parent asset to verify, so a non-transactional single INSERT suffices.
  • Express version emits no timeline_events side effects for these creates; parity preserved (pure INSERTs, no extra rows).
  • Timestamp fields (start_date / end_date / filing_date / next_hearing) use z.coerce.date() since JSON bodies carry ISO strings while drizzle-zod emits z.date(). Documented divergence inline.

Validation evidence

Typecheck

npm run check0 new errors in worker/ (pre-existing errors in server/ unchanged).

Tests — real Neon, NO MOCKS

Ran full worker integration suite on an ephemeral Neon branch (phase-3b-domain-writes-test on project steep-cloud-28172078, deleted after run):

Test Files  9 passed (9)
     Tests  64 passed (64)
  Duration  16.15s

New file worker/__tests__/domain-writes.integration.test.ts adds 17 tests covering 201/400/401/404 paths, server-owned-field stripping, intruder rejection, bad-UUID rejection, and invalid-JSON rejection across all three routes. Fixture suffixes 5E / 5F chosen to avoid collision with existing 5A..5L identities.

Wrangler dry-run

npx wrangler deploy --dry-run --env production
Total Upload: 596.63 KiB / gzip: 119.92 KiB
--dry-run: exiting now.

All bindings present (Hyperdrive, Assets, all CHITTYAUTH/MINT/CONNECT/LEDGER env vars, tail to chittytrack).

Neon MCP transaction validation (BEGIN/ROLLBACK)

Executed live against the test branch via Neon MCP run_sql_transaction, ending with ROLLBACK. All three INSERTs returned real rows:

  • warranty: { id: 3ecd6bb9-..., asset_id: e3e01c03-..., provider: "AppleCare+", is_active: true }
  • insurance_policy: { id: dec0d78e-..., policy_number: "CHUBB-VAL-001" }
  • legal_case: { id: 7e8f4972-..., case_number: "2025-CV-VAL-001", title: "Phase 3b validation case" }

Test plan

  • npm run check — 0 new worker errors
  • Full worker integration suite green (64/64)
  • npx wrangler deploy --dry-run --env production succeeds
  • Live Neon transaction (BEGIN/INSERT×3/ROLLBACK) validates schema parity
  • After merge, smoke-test live endpoints via curl assets.chitty.cc/api/v1/status to confirm migration_status: "PHASE_3B_DOMAIN_WRITES" and new routes listed

Divergences from Express

  1. z.coerce.date() extension on timestamp fields — Express's body-parser path silently passed strings through Drizzle; we make coercion explicit in Hono.
  2. No timeline_events rows emitted (matches Express — flagged because Phase 3a evidence/asset writes DO emit them).

🤖 Generated with Claude Code

…al-cases creates)

Ports the three remaining domain write routes from Express to Hono:
  POST /api/assets/:assetId/warranties   (server/routes.ts:476)
  POST /api/assets/:assetId/insurance    (server/routes.ts:508)
  POST /api/legal-cases                  (server/routes.ts:540)

Pattern mirrors Phase 3a evidence attach:
- Zod input schemas omit server-owned fields (userId / assetId-from-URL /
  chittyId) so clients cannot spoof them.
- For warranties + insurance, parent-asset ownership is verified inside the
  same transaction as the INSERT (SELECT id FROM assets WHERE id=? AND
  user_id=?), returning 404 on mismatch — no existence leak.
- For legal_cases, user_id is server-injected from claims; no parent asset.
- Express version emits no timeline_events side effects for these creates;
  parity preserved (pure INSERTs).
- Timestamp columns (start_date / end_date / filing_date / next_hearing) are
  coerced via z.coerce.date() since JSON carries ISO strings while
  drizzle-zod emits z.date(). Documented divergence from raw insertSchema.

Stacks on #39#38#37#36#34#33.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bb4e0ecc-333a-477a-bd11-61a8dd8c5199

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 feat/hono-phase-3b-domain-writes

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.

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.

1 participant