DreamWeaverJournal.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

/**
 * @title DreamWeaverJournal
 * @notice Stores journal entries generated by the DreamWeaver AI upon reaching evolution milestones.
 * @dev Entries are added by the contract owner (acting as the AI's oracle).
 *      Entries are linked to the corresponding evolution level and optionally the state hash anchor transaction.
 */
contract DreamWeaverJournal is
    Initializable,
    OwnableUpgradeable,
    UUPSUpgradeable
{
uint256 private _entryIds;



    // Structure for each journal entry
    struct JournalEntry {
        uint256 id;          // Unique ID for the entry
        uint256 level;       // AI evolution level at the time of writing
        string entryText;    // The AI-generated journal text
        uint256 timestamp;   // Timestamp when the entry was recorded on-chain
        bytes32 anchorTxHash; // Optional: Tx hash from DreamWeaverGraph.updateGraphState for this level
        address recorder;    // Address that recorded the entry (owner/oracle)
    }

    // Array to store all journal entries chronologically
    JournalEntry[] public entries;

    // Mapping from entry ID to its index in the entries array for quick lookup
    mapping(uint256 => uint256) private _entryIndexById;
    
    // Mapping to track if an entry ID exists
    mapping(uint256 => bool) private _entryExists;

    // Event emitted when a new entry is added
    event EntryAdded(
        uint256 indexed entryId,
        uint256 indexed level,
        uint256 timestamp,
        bytes32 anchorTxHash,
        address recorder
    );

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /**
     * @notice Initializes the contract.
     * @param initialOwner The initial owner (oracle address).
     */
    function initialize(address initialOwner) public initializer {
        __Ownable_init(initialOwner);
        __UUPSUpgradeable_init();
    }

    /**
     * @dev Required for UUPS upgradeability. Only owner can authorize upgrades.
     */
    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}

/**
 * @notice Adds a new journal entry. Only callable by the owner (oracle).
 * @param _level The AI evolution level for this entry.
 * @param _entryText The AI-generated text for the journal.
 * @param _anchorTxHash Optional transaction hash from the corresponding state anchor. Use bytes32(0) if not applicable.
 */
function addEntry(
    uint256 _level,
    string memory _entryText,
    bytes32 _anchorTxHash
) external onlyOwner {
    _entryIds += 1;
    uint256 newEntryId = _entryIds;

    JournalEntry memory newEntry = JournalEntry({
        id: newEntryId,
        level: _level,
        entryText: _entryText,
        timestamp: block.timestamp,
        anchorTxHash: _anchorTxHash,
        recorder: msg.sender
    });

    entries.push(newEntry);
    _entryIndexById[newEntryId] = entries.length - 1;
    _entryExists[newEntryId] = true;

    emit EntryAdded(
        newEntryId,
        _level,
        block.timestamp,
        _anchorTxHash,
        msg.sender
    );
}

    /**
     * @notice Gets the total number of journal entries recorded.
     * @return The count of entries.
     */
    function getEntryCount() external view returns (uint256) {
        return entries.length;
    }

    /**
     * @notice Retrieves a specific journal entry by its index in the chronological array.
     * @param _index The index of the entry (0 to getEntryCount() - 1).
     * @return The JournalEntry struct.
     */
    function getEntryByIndex(uint256 _index) external view returns (JournalEntry memory) {
        require(_index < entries.length, "DreamWeaverJournal: Index out of bounds");
        return entries[_index];
    }

     /**
     * @notice Retrieves a specific journal entry by its unique ID.
     * @param _entryId The unique ID of the entry.
     * @return The JournalEntry struct.
     */
    function getEntryById(uint256 _entryId) external view returns (JournalEntry memory) {
        require(_entryExists[_entryId], "DreamWeaverJournal: Invalid entry ID");
        return entries[_entryIndexById[_entryId]];
    }
}