Notice: 2025-06-14

Development progress is summarized here.

https://zenn.dev/nakamura196/books/41693d2d017082

Overview

Starting with the following article, I have been prototyping a digital cultural heritage management system using blockchain.

This time, I modified the system so that uploaded data is recognized as NFTs.

This is a learning process, so there may be incomplete aspects, but I hope it serves as a helpful reference.

Usage Page

The file upload method remains the same as before. A link to the detail page was added to the list page displayed after upload.

Clicking the link navigates to the following detail screen.

Implementation

This section was written by AI.

1. Making the Contract NFT-Compatible

The existing digital cultural heritage management contract was modified to comply with the ERC721 standard as an NFT contract.

Main Changes:

1. Adding OpenZeppelin Libraries

import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";

2. Changing the Contract Inheritance Structure

contract DigitalHeritage is
    Initializable,
    OwnableUpgradeable,
    UUPSUpgradeable,
    ERC721Upgradeable,
    ERC721URIStorageUpgradeable
{
    // ...
}

3. Updating the Initialization Function

function initialize() public initializer {
    __Ownable_init(msg.sender);
    __UUPSUpgradeable_init();
    __ERC721_init("Digital Heritage", "DH");
    __ERC721URIStorage_init();
}

4. NFT Minting on Cultural Heritage Registration

function registerHeritage(
    string memory _name,
    string memory _description,
    string memory _imageUrl,
    string memory _tokenURI
) public {
    uint256 id = heritages.length;

    // Save cultural heritage data
    heritages.push(Heritage({
        id: id,
        name: _name,
        description: _description,
        imageUrl: _imageUrl,
        owner: msg.sender,
        timestamp: block.timestamp,
        isDeleted: false
    }));

    // Mint as NFT
    _safeMint(msg.sender, id);
    _setTokenURI(id, _tokenURI);

    emit HeritageRegistered(id, msg.sender, _name);
}

2. Implementing the Metadata Management System

To support the standard NFT metadata format, server-side metadata generation and upload functionality was implemented.

1. Metadata Generation in API Route

// src/app/api/upload/route.js
const uploadMetadataToPinata = async (name, description, imageUrl) => {
  const metadata = {
    name: name,
    description: description,
    image: imageUrl,
    attributes: [
      {
        trait_type: "Registration Date",
        value: new Date().toISOString()
      },
      {
        trait_type: "Category",
        value: "Digital Cultural Heritage"
      }
    ]
  };

  // Convert JSON to Blob and upload to Pinata
  const jsonBlob = new Blob([JSON.stringify(metadata, null, 2)], {
    type: 'application/json'
  });

  // Upload to IPFS using Pinata API
  // ...
};

2. Frontend Integration

// Flow: Image upload -> Metadata generation -> Contract registration
const handleSubmit = async (e) => {
  // 1. Upload image to IPFS
  const imageUrl = formData.imageUrl;

  // 2. Generate and upload metadata on the server side
  const metadataFormData = new FormData();
  metadataFormData.append('type', 'metadata');
  metadataFormData.append('name', formData.name);
  metadataFormData.append('description', formData.description);
  metadataFormData.append('imageUrl', imageUrl);

  const metadataResponse = await fetch('/api/upload', {
    method: 'POST',
    body: metadataFormData
  });

  const metadataResult = await metadataResponse.json();

  // 3. Register with the contract (including token URI)
  await registerHeritage(
    formData.name,
    formData.description,
    imageUrl,
    metadataResult.url
  );
};

Summary

I hope this serves as a helpful reference in the process of learning Web3 and NFTs.