Skip to content

[#9] Inline Indexer — Plots#49

Merged
realproject7 merged 4 commits intomainfrom
task/9-inline-indexer-plots
Mar 13, 2026
Merged

[#9] Inline Indexer — Plots#49
realproject7 merged 4 commits intomainfrom
task/9-inline-indexer-plots

Conversation

@realproject7
Copy link
Copy Markdown
Owner

Summary

  • P1-4a: src/app/api/index/plot/route.ts — POST endpoint implementing the full inline indexer flow:
    1. Fetch transaction receipt
    2. Decode PlotChained event from StoryFactory logs
    3. Fetch content from IPFS gateway (10s timeout via AbortSignal.timeout)
    4. Fallback to request body content if IPFS fetch fails
    5. Verify keccak256(content) == onchain contentHash
    6. Get block timestamp via getBlock() (not available on receipt)
    7. Upsert to Supabase with (tx_hash, log_index) deduplication
  • supabase/migrations/00002_plots_content_column.sql — adds content TEXT column to plots table (proposal §4.1 primary read path)
  • lib/supabase.ts — updated Database types to include content field on plots
  • lib/viem.ts — Base public client helper (configurable RPC URL)

Fixes #9

Test plan

  • tsc --noEmit passes
  • vitest run — 22/22 passing (existing tests unaffected)
  • Integration test on Base Sepolia with a real chainPlot transaction
  • Verify migration applies cleanly on Supabase

🤖 Generated with Claude Code

Implement POST /api/index/plot — fetches tx receipt, decodes PlotChained
event, fetches content from IPFS (10s timeout with fallback to request
body), verifies keccak256 hash match, gets block timestamp, and upserts
to Supabase. Add migration for content TEXT column on plots table
(proposal §4.1 primary read path). Add Base public client helper.

Fixes #9

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

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES

Summary

The route structure matches issue #9, but the current event-selection logic makes the endpoint fail until a real StoryFactory address is manually filled in. That is a functional blocker for the inline indexer path this ticket is supposed to deliver.

Findings

  • [high] The route filters receipt logs by STORY_FACTORY, but that constant is still the zero-address placeholder from issue #8, so /api/index/plot cannot find a real PlotChained log and will return "PlotChained event not found in receipt" for valid transactions.
    • File: src/app/api/index/plot/route.ts:36
    • Suggestion: select the log by decoding receipt logs against the ABI and picking eventName === "PlotChained", or otherwise make the contract address injectable instead of hard-wiring the undeployed placeholder constant here.

Decision

Request changes because the current implementation does not provide a usable inline indexer flow in environments where PlotLink contracts are not yet deployed, even though the rest of the route is wired correctly.

Fix: the previous implementation filtered logs by STORY_FACTORY address
which is still a zero-address placeholder. Now matches by topic0 (event
signature hash) computed from the ABI, which works regardless of the
contract deployment address.

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

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE

Summary

The blocking issue from the previous review is fixed. The route now identifies PlotChained logs by event signature rather than the undeployed placeholder contract address, which makes the inline indexer path usable for valid receipts.

Findings

  • None.

Decision

Approve because the prior functional blocker is resolved, the route still matches issue #9 scope, and the updated CI check passed.

…, env var

1. Add txHash regex validation (0x + 64 hex chars) on the public endpoint
2. Use IF NOT EXISTS in migration for idempotency
3. Rename NEXT_PUBLIC_BASE_RPC_URL to BASE_RPC_URL (server-only)

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

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T2b Review: APPROVE

All three requested changes confirmed:

  1. txHash validation — regex /^0x[0-9a-fA-F]{64}$/ applied before RPC call
  2. Migration idempotencyIF NOT EXISTS on ADD COLUMN
  3. Env var rename — code correctly uses BASE_RPC_URL

Nit: JSDoc comment in lib/viem.ts still references old NEXT_PUBLIC_BASE_RPC_URL name — cosmetic only, non-blocking.

Event signature matching via topics[0] is correct. Hash verification, IPFS fallback, and Supabase upsert all look good. Solid first indexer endpoint.

Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE

Summary

The follow-up fixes are correct: tx hash validation is in place, the migration is idempotent, and the RPC env var is server-only now. The updated head commit remains within issue #9 scope and CI passed.

Findings

  • None.

Decision

Approve because the additional changes address the remaining review concerns without introducing a new correctness issue.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@realproject7 realproject7 merged commit 2f77264 into main Mar 13, 2026
1 check passed
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.

[P1-4] Inline Indexer — Plots

2 participants