Skip to content

Latest commit

 

History

History
231 lines (174 loc) · 7.1 KB

File metadata and controls

231 lines (174 loc) · 7.1 KB

Tagging Feature Documentation

Overview

The tagging feature allows users to organize and categorize their savings goals, bills, and insurance policies using custom string labels (tags). This enables better grouping, filtering, and analytics across all financial entities.

Implementation

Data Model Changes

Tags have been added to the following structs:

  1. Bill (bill_payments/src/lib.rs)

    • Added tags: Vec<String> field
    • Tags are preserved when bills are archived
    • Tags are copied to recurring bills
  2. ArchivedBill (bill_payments/src/lib.rs)

    • Added tags: Vec<String> field
    • Tags are preserved from the original bill
  3. SavingsGoal (savings_goals/src/lib.rs)

    • Added tags: Vec<String> field
  4. InsurancePolicy (insurance/src/lib.rs)

    • Added tags: Vec<String> field

Tag Management Functions

Each contract provides owner-only functions to manage tags:

Bill Payments Contract

pub fn add_tags_to_bill(
    env: Env,
    caller: Address,
    bill_id: u32,
    tags: Vec<String>,
) -> Result<(), Error>

pub fn remove_tags_from_bill(
    env: Env,
    caller: Address,
    bill_id: u32,
    tags: Vec<String>,
) -> Result<(), Error>

Savings Goals Contract

pub fn add_tags_to_goal(
    env: Env,
    caller: Address,
    goal_id: u32,
    tags: Vec<String>,
)

pub fn remove_tags_from_goal(
    env: Env,
    caller: Address,
    goal_id: u32,
    tags: Vec<String>,
)

Insurance Contract

pub fn add_tags_to_policy(
    env: Env,
    caller: Address,
    policy_id: u32,
    tags: Vec<String>,
)

pub fn remove_tags_from_policy(
    env: Env,
    caller: Address,
    policy_id: u32,
    tags: Vec<String>,
)

Tag Validation and Canonicalization

All contracts enforce consistent validation and normalization rules to ensure safe indexing and predictable off-chain search behavior:

Validation Rules

  • Tags cannot be empty (at least one tag must be provided)
  • Each tag must be between 1 and 32 characters in length
  • Allowed character set: [a-z0-9-_] (lowercase letters, digits, hyphens, underscores)
  • Uppercase letters are automatically normalized to lowercase
  • Duplicate tags are allowed

Canonicalization Process

Tags are normalized before storage using the following rules:

  1. Case normalization: All uppercase letters (A-Z) are converted to lowercase (a-z)
  2. Character validation: Only alphanumeric characters, hyphens (-), and underscores (_) are allowed
  3. Length validation: Tags must be 1-32 characters after normalization
  4. Rejection: Tags with invalid characters (e.g., @, !, #, spaces) are rejected with an error

Shared helpers (remitwise-common)

Tag validation is centralized in remitwise-common:

  • canonicalize_tags_checked(env, tags) -> Result<Vec<String>, TagError> — preferred for untrusted or indexer-supplied input. Returns typed errors (Empty, TooLong, InvalidChar { position }) and short-circuits on the first violation.
  • canonicalize_tags(env, tags, on_invalid_char) — legacy panic-based wrapper retained for backward compatibility. New contract code should prefer the checked variant and map TagError to each crate's contract errors (e.g. SavingsGoalError::InvalidTagContent).

TAG_MAX_LEN (32) in remitwise-common is the single source of truth for maximum tag length.

Examples

  • "URGENT-1_Tag""urgent-1_tag" (normalized)
  • "Monthly-Bill""monthly-bill" (normalized)
  • "invalid@tag!"rejected (invalid characters)
  • ""rejected (empty)
  • "a" * 33rejected (too long)

Events

Tag operations emit events for tracking and analytics:

Bill Payments

  • tags_add: Emitted when tags are added to a bill
    • Data: (bill_id, owner, tags)
  • tags_rem: Emitted when tags are removed from a bill
    • Data: (bill_id, owner, tags)

Savings Goals

  • tags_add: Emitted when tags are added to a goal
    • Data: (goal_id, owner, tags)
  • tags_rem: Emitted when tags are removed from a goal
    • Data: (goal_id, owner, tags)

Insurance

  • tags_add: Emitted when tags are added to a policy
    • Data: (policy_id, owner, tags)
  • tags_rem: Emitted when tags are removed from a policy
    • Data: (policy_id, owner, tags)

Authorization

  • Only the owner of an entity (bill, goal, or policy) can add or remove tags
  • All tag operations require authentication via caller.require_auth()
  • Unauthorized attempts will result in a panic or error

Storage

  • Tags are stored as part of the entity struct
  • Tags are included in all query results (paginated and single-entity queries)
  • Tags persist across entity lifecycle (e.g., when bills are archived)
  • Tags are copied to recurring bills when a bill is paid

Usage Examples

Adding Tags to a Bill

let tags = vec![
    String::from_str(&env, "utilities"),
    String::from_str(&env, "monthly"),
    String::from_str(&env, "high-priority")
];

client.add_tags_to_bill(&owner, &bill_id, &tags);

Removing Tags from a Savings Goal

let tags_to_remove = vec![
    String::from_str(&env, "old-tag")
];

client.remove_tags_from_goal(&owner, &goal_id, &tags_to_remove);

Adding Tags to an Insurance Policy

let tags = vec![
    String::from_str(&env, "health"),
    String::from_str(&env, "family")
];

client.add_tags_to_policy(&owner, &policy_id, &tags);

Integration with Existing Features

Pagination

Tags are automatically included in all paginated query results:

  • get_unpaid_bills
  • get_all_bills_for_owner
  • get_archived_bills
  • get_active_policies
  • get_goals

Archiving

When bills are archived, their tags are preserved in the ArchivedBill struct.

Recurring Bills

When a recurring bill is paid and a new bill is created, the tags are copied to the new bill.

Error Handling

Bill Payments Contract

  • Error::EmptyTags (14): Panics when trying to add/remove an empty tag list
  • Error::InvalidTag (13): Panics when a tag is invalid (empty or > 32 characters)
  • Error::InvalidTagContent (19): Panics when a tag contains invalid characters (not in [a-z0-9-_])
  • Error::Unauthorized (5): Panics when a non-owner tries to modify tags
  • Error::BillNotFound (1): Panics when the bill doesn't exist

Savings Goals & Insurance Contracts

These contracts use panics for error handling:

  • "Tags cannot be empty": When trying to add/remove an empty tag list
  • "Tag must be between 1 and 32 characters": When a tag is invalid
  • SavingsGoalError::InvalidTagContent: When a tag contains invalid characters
  • "Only the [entity] owner can [add/remove] tags": When unauthorized
  • "[Entity] not found": When the entity doesn't exist

Future Enhancements

Potential improvements for the tagging system:

  1. Tag-based Filtering: Add query functions to filter entities by tags
  2. Tag Analytics: Aggregate statistics by tag (e.g., total amount by tag)
  3. Tag Suggestions: Auto-suggest tags based on entity names or patterns
  4. Tag Limits: Enforce maximum number of tags per entity
  5. Predefined Tags: Support for system-defined tag categories
  6. Tag Search Index: On-chain search index for tag-based queries