Skip to content

Feat/artwork flows - #20

Merged
dan13ram merged 22 commits into
mainfrom
feat/artwork-flows
Sep 28, 2026
Merged

dan13ram merged 22 commits into
mainfrom
feat/artwork-flows

Conversation

@dan13ram

Copy link
Copy Markdown
Collaborator

No description provided.

dan13ram and others added 22 commits September 28, 2026 13:49
Implement comprehensive artwork management for Stellar DAO builder:

## New Components
- ArtworkPlayground: Interactive layer ordering with real-time canvas preview
- LayerOrdering: Drag-and-drop layer reordering with keyboard support
- ArtworkPreviewCanvas: Canvas-based composite image rendering
- ArtworkSourceStep: Multi-mode artwork source selection (upload/generate/starter)
- ArtworkDirectoryUpload: Directory upload with validation and Pinata integration
- DaoImageField: Reusable image field component for artwork configuration

## New Services & Utilities
- PinataService: IPFS upload/management via Pinata API
- AIImageGeneration: Integrated AI image generation for artwork
- StarterCollections: Pre-configured artwork collections
- FileHash: Content-addressed file deduplication
- UploadCache: Browser-based upload state persistence
- DaoDeploymentValidation: Pre-deployment validation checks

## New API Routes
- /api/uploads/*: Artwork upload management and processing
- /api/artwork/*: Artwork metadata and transformation
- /api/pinata/*: Pinata gateway configuration and validation

## Integration Features
- Full layer reordering with preview
- Upload → Playground → Store → Contract flow
- Order preservation through contract parameters
- IPFS gateway configuration with security validation
- Real-time preview canvas during layer editing

## Documentation
- ARTWORK_PLAYGROUND_INTEGRATION.md: Complete integration guide
- DAO_CREATION_ARTWORK_PLAN.md: System architecture and requirements

All artwork configuration flows through:
1. Upload or select artwork source
2. Preview and reorder layers in Playground
3. Save to Zustand store with correct ordering
4. Transform to contract parameters (property_id by array index)
5. Deploy to metadata contract with on-chain storage

The layer order in Playground directly determines rendering order in final token images.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
Fix auth rate limiting to work in local development by adding fallback IP detection.

## Problem
Rate limiting was only checking x-vercel-forwarded-for header, which doesn't exist
in local development. This caused all auth requests to fail with 503 "Unable to
identify the requesting client." error.

## Solution
Implement robust IP detection with fallback chain:
1. x-vercel-forwarded-for (Vercel production)
2. x-forwarded-for (standard proxy header)
3. x-real-ip (nginx/other reverse proxies)
4. cf-connecting-ip (Cloudflare)
5. localhost-dev identifier (local development only)
6. Fail closed in production if no valid IP found

## Changes
- Updated getClientKey() to check multiple headers in priority order
- Added NODE_ENV check to use 'localhost-dev' identifier in development
- Maintained production security: still fails closed without valid IP
- Added comprehensive test coverage for all fallback scenarios

## Tests
All 8 tests passing:
✓ Challenge claim and concurrent protection
✓ x-vercel-forwarded-for rate limiting
✓ x-forwarded-for fallback
✓ x-real-ip fallback
✓ cf-connecting-ip fallback
✓ Header priority enforcement
✓ Production fail-closed behavior
✓ Development localhost fallback

Auth endpoints now work in local development while maintaining production security.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
- Add Privacy Policy, Terms & Conditions, and Disclaimer pages with minimal, readable content
- Extract DashboardHeader and DashboardFooter into reusable shared components
- Consolidate footer across dashboard, DAO pages, and legal pages with consistent legal links
- All pages now use the same navigation and footer for consistency
- Legal documents feature web3-friendly language addressing blockchain, DAOs, and smart contract risks

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
…dao-shell

- Create reusable NetworkIndicator component that displays network label with visual dot
- Only shows when wallet is connected (when user has authenticated)
- Bring back network chip in dao-shell header showing current network
- Makes network connection status clearly visible to users in DAO context

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
…l fixes

Linting fixes applied:
1. **React Hooks Architecture (ArtworkPreviewCanvas.tsx)**:
   - Extract utility functions (getGatewayUrl, buildLayerUrl, loadImage) outside component
   - Wrap async functions (loadLayers, renderCanvas) with useCallback for proper memoization
   - Properly handle async operations in useEffect with IIFE pattern and cleanup
   - Add isMounted flag to prevent state updates on unmounted components

2. **Unused Variables**:
   - Prefix unused function parameters with underscore convention (_isGenerating, _maxConcurrent)
   - Remove unused state declarations (previewTokenIds in ArtworkDirectoryUpload)
   - Refactor unused session variables - keep authentication checks without assignment
   - Prefix unused types with underscore (_PinCidRequest, _PinataUrlRequest)

3. **Error Handling**:
   - Fix errorData assignment in ArtworkDirectoryUpload - use void expression for intentional parse

4. **Image Optimization**:
   - Add eslint-disable-next-line comments for dynamic image URLs that cannot be optimized through Next.js Image API
   - Includes fallback/error handling image URLs and AI-generated preview images

5. **Code Quality**:
   - Remove unused parameters (onGeneratingChange in LayerOrdering)
   - Remove unused local variables (deltaY - position detection uses e.clientY directly)
   - Unused store selectors removed (clearDaoImageSource, setValidationError)

All changes follow React best practices:
- Proper dependency management in hooks
- Memory leak prevention with cleanup functions
- Correct async/await patterns in effects
- Proper state management without cascading renders

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed ArtworkPlayground: removed unused isGenerating prop passed to ArtworkPreviewCanvas
- Fixed LayerOrdering: removed unused parameter destructuring
- Fixed pinata-service: removed duplicate pinByHash property in JWT permissions config
- Fixed pinata-upload: typed allowedMimes as readonly string[] to match const assertion
- Fixed dao-deployment-validation: exported CreateDaoStore type from store, imported directly, added type annotations to filter/map callbacks
- Fixed security.test.ts: replaced direct NODE_ENV assignments with Object.defineProperty to work with read-only property
- Exported CreateDaoStore type from create-dao-store for reusability

All changes maintain architectural integrity and follow TypeScript best practices. Achieved clean `pnpm typecheck` with zero errors.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
…ADS_ENABLED is disabled

Add feature flag check to conditionally render the "Upload Your Collection" section in ArtworkSourceStep. When NEXT_PUBLIC_PINATA_UPLOADS_ENABLED is not set to 'true', users will only see the "Starter Collections" option, preventing confusion from attempting uploads that will fail.

This matches the existing pattern used in DaoImageField.tsx for other feature-flagged upload options.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
…ions

Extend artwork playground to support both starter and uploaded collections using the same structured property format.

**Changes:**
- Extended ArtworkSource type to include full metadata (baseUri, extension, properties, gatewayUrl) for starter collections
- Updated ArtworkSourceStep to load starter collection data and automatically show playground after selection
- Modified playground condition to accept both 'starter' and 'uploaded' source kinds
- Updated setArtworkSource store action to sync artwork config from both source types
- Renamed type to PlaygroundArtworkSource to reflect support for both kinds
- Updated ArtworkPreviewCanvas to accept both starter and uploaded sources

**User Experience:**
- Selecting a starter collection now shows the playground for layer reordering
- Users can customize layer order before finalizing, just like with uploaded collections
- Artwork properties follow the same shape as test-dao configuration

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
Update ArtworkPreviewCanvas to use loadImageWithFallback for robust
image loading with automatic gateway fallback mechanism. This ensures
the preview canvas can gracefully handle single gateway failures by
retrying across multiple IPFS gateways.

Changes:
- Import loadImageWithFallback from lib/image-loader
- Replace direct fetch with fallback mechanism (15s timeout for previews)
- Simplify loadImage function to delegate to robust utility
- Remove redundant null checks in loadLayers

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
…anvas

Extract canvas rendering logic into a custom hook for better separation of concerns.
The hook manages layer loading, canvas rendering, and error handling in a reusable way.

Changes:
- Create useArtworkPreview hook with canvas rendering logic
- Refactor ArtworkPreviewCanvas to use the new hook (28 LOC reduction)
- Move URL building and image loading logic into hook
- Improve dependency tracking in useCallback and useEffect
- Hook returns state and reload function for component use

Benefits:
- Cleaner component code
- Reusable preview logic across the app
- Better testability
- Proper React hook patterns (no eslint-disable needed)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
Create client-safe IPFS utilities and a hook for loading images with
gateway fallback. Separates server-only DNS validation from client-safe
URL handling.

Changes:
- Create ipfs-client.ts with client-safe IPFS utilities
- Refactor image-loader to use ipfs-client instead of ipfs-gateway
- Create useFallbackSrc hook for flexible image loading
- Hook converts loaded images to data URLs for reliable display
- Includes retry capability and progress callbacks
- All state updates are properly guarded with isMounted checks

Benefits:
- Reusable across any component that needs IPFS images
- Graceful fallback when gateways fail
- No server-side code in client components
- Prevents memory leaks with cleanup

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
builder-stellar-web Ready Ready Preview Sep 28, 2026 1:50pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 28, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 446d1b85-ba27-4544-920c-898021668f2a

📥 Commits

Reviewing files that changed from the base of the PR and between e6add07 and 771a3b3.

⛔ Files ignored due to path filters (2)
  • apps/web/public/images/dao-logo.png is excluded by !**/*.png
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (48)
  • apps/web/.env.example
  • apps/web/package.json
  • apps/web/src/app/api/artwork/generate/route.ts
  • apps/web/src/app/api/pinata/generate-jwt/route.ts
  • apps/web/src/app/api/pinata/pin-cid/route.ts
  • apps/web/src/app/api/uploads/complete/route.ts
  • apps/web/src/app/api/uploads/pinata-url/route.ts
  • apps/web/src/app/disclaimer/page.tsx
  • apps/web/src/app/privacy/page.tsx
  • apps/web/src/app/terms/page.tsx
  • apps/web/src/components/create-dao/ArtworkDirectoryUpload.tsx
  • apps/web/src/components/create-dao/ArtworkPlayground.tsx
  • apps/web/src/components/create-dao/ArtworkPreviewCanvas.tsx
  • apps/web/src/components/create-dao/ArtworkSourceStep.tsx
  • apps/web/src/components/create-dao/ArtworkStep.tsx
  • apps/web/src/components/create-dao/BasicInfoStep.tsx
  • apps/web/src/components/create-dao/DaoImageField.tsx
  • apps/web/src/components/create-dao/LayerOrdering.tsx
  • apps/web/src/components/create-dao/ReviewStep.tsx
  • apps/web/src/components/create-dao/TraitSelector.tsx
  • apps/web/src/components/dao-shell.tsx
  • apps/web/src/components/dashboard/dashboard-footer.tsx
  • apps/web/src/components/dashboard/dashboard-header.tsx
  • apps/web/src/components/dashboard/dashboard-shell.tsx
  • apps/web/src/components/network-indicator.tsx
  • apps/web/src/components/ui/FallbackImage.tsx
  • apps/web/src/components/ui/index.ts
  • apps/web/src/hooks/useArtworkPreview.ts
  • apps/web/src/hooks/useFallbackSrc.ts
  • apps/web/src/lib/ai-image-generation.ts
  • apps/web/src/lib/auth/rate-limit.ts
  • apps/web/src/lib/auth/security.test.ts
  • apps/web/src/lib/auth/server.ts
  • apps/web/src/lib/dao-deployment-validation.ts
  • apps/web/src/lib/file-hash.ts
  • apps/web/src/lib/image-loader.ts
  • apps/web/src/lib/ipfs-client.ts
  • apps/web/src/lib/pinata-service.ts
  • apps/web/src/lib/pinata-upload-auth.test.ts
  • apps/web/src/lib/pinata-upload-auth.ts
  • apps/web/src/lib/pinata-upload.test.ts
  • apps/web/src/lib/pinata-upload.ts
  • apps/web/src/lib/starter-collections.ts
  • apps/web/src/lib/upload-cache.ts
  • apps/web/src/lib/validation.ts
  • apps/web/src/stores/create-dao-store.ts
  • docs/ARTWORK_PLAYGROUND_INTEGRATION.md
  • docs/DAO_CREATION_ARTWORK_PLAN.md
 ____________________________________
< Come with me if you want to debug. >
 ------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@dan13ram
dan13ram merged commit e2c8f7a into main Sep 28, 2026
2 of 3 checks passed

This branch was successfully deployed

1 active deployment
Preview — 771a3b38 Deployed Sep 28, 2026 by vercel[bot]
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