Personal Goal Accountability Contract

What it does:
Allows individuals to define personal goals, set milestones, and record progress on-chain, optionally linking incentives or penalties to goal completion.

Why it matters:
Encourages discipline, provides transparent accountability, prevents tampering with progress records, and can automate rewards for achieving goals.

How it works:

  • Users register personal goals with target metrics, deadlines, and optional stakes

  • Milestones are tracked, and progress is submitted and verified by validators or trusted peers

  • Smart contract can release rewards, penalties, or NFTs based on milestone completion

  • Immutable history provides verifiable accountability over time

  • Integrates with Relationship Agreements, Time-Capsule Messages, or tokenized reward systems

  • Dashboards visualize goals, milestones, progress, and achievements

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

import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title PersonalGoalAccountability
 * @author Nam
 * @notice Tracks personal goals and milestones with optional rewards on-chain
 */
contract PersonalGoalAccountability is Ownable {

    struct Milestone {
        string description;
        uint256 dueDate; // timestamp
        bool completed;
    }

    struct Goal {
        address user;
        string title;
        Milestone[] milestones;
        uint256 reward; // optional ETH reward for completion
        bool completed;
    }

    mapping(uint256 => Goal) public goals;
    uint256 public goalCount;

    mapping(address => bool) public authorizedValidators;

    // -------------------- EVENTS --------------------

    event ValidatorApproved(address validator);
    event ValidatorRevoked(address validator);
    event GoalCreated(uint256 indexed goalId, address user, string title);
    event MilestoneCompleted(uint256 indexed goalId, uint256 milestoneIndex);
    event GoalCompleted(uint256 indexed goalId, address user, uint256 reward);

    // -------------------- VALIDATOR MANAGEMENT --------------------

    function approveValidator(address _validator) external onlyOwner {
        authorizedValidators[_validator] = true;
        emit ValidatorApproved(_validator);
    }

    function revokeValidator(address _validator) external onlyOwner {
        authorizedValidators[_validator] = false;
        emit ValidatorRevoked(_validator);
    }

    modifier onlyValidator() {
        require(authorizedValidators[msg.sender], "Not authorized validator");
        _;
    }

    // -------------------- GOAL MANAGEMENT --------------------

    function createGoal(string calldata _title, string[] calldata _milestoneDescriptions, uint256[] calldata _dueDates) external payable {
        require(_milestoneDescriptions.length == _dueDates.length, "Mismatched milestones and dates");

        goalCount += 1;
        Goal storage g = goals[goalCount];
        g.user = msg.sender;
        g.title = _title;
        g.reward = msg.value;
        g.completed = false;

        for (uint256 i = 0; i < _milestoneDescriptions.length; i++) {
            g.milestones.push(Milestone({
                description: _milestoneDescriptions[i],
                dueDate: _dueDates[i],
                completed: false
            }));
        }

        emit GoalCreated(goalCount, msg.sender, _title);
    }

    // -------------------- MILESTONE MANAGEMENT --------------------

    function completeMilestone(uint256 _goalId, uint256 _milestoneIndex) external onlyValidator {
        Goal storage g = goals[_goalId];
        require(!g.completed, "Goal already completed");

        Milestone storage m = g.milestones[_milestoneIndex];
        require(!m.completed, "Milestone already completed");

        m.completed = true;
        emit MilestoneCompleted(_goalId, _milestoneIndex);

        // Check if all milestones completed
        bool allCompleted = true;
        for (uint256 i = 0; i  0) {
                payable(g.user).transfer(g.reward);
            }
            emit GoalCompleted(_goalId, g.user, g.reward);
        }
    }

    // -------------------- VIEW FUNCTIONS --------------------

    function getMilestones(uint256 _goalId) external view returns (Milestone[] memory) {
        return goals[_goalId].milestones;
    }

    function isGoalCompleted(uint256 _goalId) external view returns (bool) {
        return goals[_goalId].completed;
    }

    // -------------------- FUNDING --------------------

    receive() external payable {}
}