Skip to content

Commit 58ba648

Browse files
0xBigBossbeezybargclaude
authored
feat(sendtag): implement multiple sendtags with main tag selection (#1568)
* Initial changes for send_Account_tags * This commit adds the ability for the user to set their main sendtag -- By default it will be set to their first confirmed tag. Prepare for multiple send_accounts and better tag association.Change linking of tags to user from tag -> user_id to tag.id -> send_account_tags.tag_id -> send_account_tags.user_id -> send_accounts.user_id Add the ability for the user to delete tags , which will in turn make them a new status of 'available'. Added create_tag function and updated confirm_tags to use send_accounts when confirming the tags. Updated profile view and activity view to display the users main sendtag when we display their activity/referrals ..etc * Add snaplet datamodel updated * Add tags.create to trpc mutation, update code and tests to use it. * Have user deposit USDC if balance is not enough to afford tags * fix playwright tests * Fix activity home feed layout, there was annoying bug where inner items in list view were not aligned with the main indentation of the first and last item causing a staggered appearance * Add main tag pill on account overview , fix styling and flow of delete sendtag and setting main sendtag * Add changes for BBVIBE * Implement main tag sorting for sendtags and update UI components to reflect main tag status across the app * Add detailed feature documentation for send account tags, including architecture, phases, critical issues, and quick start guide * Refactor database schema for send account tags, adding migrations for tag ID handling and improving tag status management * chore: move to declarative * Refactor database schema, removing unused fields and functions while improving tag association handling and status management * Refactor tag RLS policies and activity feed view, ensuring accurate user access control and tag handling in the database * clean up after rebase * fix failing tests * more test fixes * lots o cleanup * add comprehensive guide for sendtags system including use cases, database schema, and lifecycle management details * fix send_accounts tests to use create_tag function and ensure proper associations with user accounts in various scenarios * update tags_update_test.sql to reflect correct role permissions for updating confirmed tags in tests * squash migrations * update docs * update docs * chore: sync supabase and snaplet configs * api: handle main sendtag * fix: main sendtag api and supabase fixes * fix: enforce RLS for tag confirmations and adjust error handling for tag creation process * reconcile with original migrations * supabase: more sendtag tests * fix: supabase migrations for send account tags and more tests * refactor: remove historical_tag_associations from data model, types, and definitions for cleaner structure and maintenance * revert back to dev * fix conflicts from dev * fix tests * fix(supabase): prevent no confirmed tags on send account * refactor(seed): use external selection config for database seeding in snaplet * fix: types and add sendtag * feat(sendtag): add Main Tag selection sheet and enhance SendtagList with main tag functionality * feat(sendtag): introduce sendtag happy path test and enhance activity feed with main tag details in database schema * fix: type too large error * test: add assertion to check send account existence in anonymous user profile test * docs: review ready * feat: enhance seed script with user tagging and postgres updates for send accounts * fix: update Node.js memory limit in template and contributing docs for improved performance * feat: update seed script to set user_id for tags using send_account_tags relationships in PostgreSQL * fix: update ActivityAvatar to use main_tag_name for avatar generation and improve user name fallback logic in activity utils * test: add SQL tests for main tag functionality in activity feed for users and ensure correct behavior across scenarios * feat: refactor MainTagSelectionSheet to use Dialog component and enhance UI/UX for selecting main tags with updated overlay styles * fix: hide main_tag_id * chore: update playwright version from 1.48.2 to 1.52.0 in package.json and yarn.lock for dependency management * chore: enhance devShell in flake.nix with Playwright drivers support for Linux and improve shellHook environment setup * fix: resolve duplicate send_account_tags errors in Snaplet models - Updated send_account_tags model to properly distribute tags across relationships - Changed userOnboarded to create 2 send_account_tags (matching the 2 tags created) - Removed manual send_account_tags insertion from profile.anon.spec.ts test - Fixed unique constraint violations when seeding test data The issue was that the send_account_tags model always used the first tag and send_account, causing duplicate entries when creating multiple relationships. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * chore: remove caddy references from Brewfile, Tiltfile, flake.nix, and apps.Tiltfile to streamline dependencies and configurations * fix(playwright): tests to handle send account tags tests are still failing though * fix(snaplet): update user creation functions to handle confirmed tags and accounts - Improved user creation utilities to support multiple tags - Added specific tag name options and configuration validation - Enhanced test suite for user creation logic * fix(playwright): update tests to use new user creation functions for tags and accounts - Refactored tests to utilize createUserWithTagsAndAccounts and createUserWithoutTags - Enhanced clarity and maintainability of user setup in tests * fix(supabase): move migrations to end * fix(api): simplify code * fix(checkout): remove unused imports in checkout-confirm-button component * fix(checkout): remove unused tag creation form in the checkout-form component * fix(playwright): remove obsolete run-tests.sh script from the Playwright package * fix(playwright): comment out timeout and globalTimeout in playwright.config.ts for clarity * fix(snaplet): remove unused user creation exports from index.ts to streamline the module * fix(token-colors): remove unused color12 key from the color object to clean up the theme definitions * fix(send_account_tags): update policy conditions to use subquery for auth.uid() for better consistency and security * fix(activity_feed): drop and recreate view and functions to support new activity_feed_user type with additional fields * fix(send_account_tags): update tag_receipts to reference new tag_id and enforce not null constraint for data consistency * fix(snaplet): enhance error handling in snapshot restore and migration commands for clearer output and improved debugging * fix(tag_search): implement profile deduplication with distance-based ranking for search results Fixed tag search function to prevent duplicate profiles when users have multiple matching tags. Previously, a user with multiple tags matching a query would appear multiple times in results. Changes: - Replace DISTINCT ON(profile_id) with ROW_NUMBER() window function for proper deduplication - Use PARTITION BY profile_id ORDER BY trigram distance to keep best match per profile - Ensure exact matches (distance=0) are prioritized over partial matches - Apply LIMIT/OFFSET after deduplication and distance-based ordering - Fix syntax error in schemas/tags.sql (ranked_tags.tag_name reference) - Add comprehensive test coverage for deduplication scenarios - Create detailed documentation for tag search functionality The solution ensures one result per profile while maintaining optimal search relevance through trigram distance ranking. Exact matches appear first, followed by closest partial matches. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * docs: introduce comprehensive guide for the Sendtags system, covering architecture, lifecycle, and user functionality --------- Co-authored-by: beezy <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent 09e8c38 commit 58ba648

File tree

121 files changed

+8873
-1049
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+8873
-1049
lines changed

.env.local.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ NEXT_PUBLIC_GEOBLOCK=0
3434
# Limit turbo concurrency
3535
# TURBO_CONCURRENCY='50%'
3636
# Increase JavaScript heap size for lint jobs (prevents out of memory errors)
37-
# NODE_OPTIONS="--max-old-space-size=4096"
37+
# NODE_OPTIONS="--max_old_space_size=8192"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Brewfile.lock.json
6666

6767
# asdf
6868
.tool-versions
69+
.snaplet
6970

7071
var/**
7172

Brewfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ puts "Installing applications... (this may take a while) CI=#{CI}"
1111
brew "jq" unless system "jq --version"
1212
brew "yj" unless system "yj -v"
1313
brew "tilt" unless system "tilt version"
14-
brew "caddy" unless system "caddy version"
1514
brew "nss" unless system "nss-config --version"
1615
brew "sqlfluff" unless CI or system "sqlfluff --version"
1716
brew "postgresql" unless system "psql --version"

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ If you encounter "FATAL ERROR: Reached heap limit Allocation failed - JavaScript
133133
Add the following to your `.env.local` file:
134134

135135
```sh
136-
NODE_OPTIONS="--max-old-space-size=4096"
136+
NODE_OPTIONS="--max_old_space_size=8192"
137137
```
138138

139139
This allocates 4GB of memory for Node.js processes. You can adjust the value based on your system's available memory.

Tiltfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ load("ext://dotenv", "dotenv")
55

66
include("./tilt/preamble.tiltfile")
77

8-
require_tools("yarn", "docker", "jq", "yj", "forge", "anvil", "caddy", "node", "bun")
8+
require_tools("yarn", "docker", "jq", "yj", "forge", "anvil", "node", "bun")
99

1010
print(color.cyan("Config: " + str(CFG)))
1111

apps/next/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@
2626
"@tamagui/next-theme": "^1.126.1",
2727
"@tanstack/react-query": "^5.74.4",
2828
"@tanstack/react-query-devtools": "^5.72.1",
29-
"@trpc/client": "^11.1.0",
30-
"@trpc/next": "^11.1.0",
31-
"@trpc/react-query": "^11.1.0",
32-
"@trpc/server": "^11.1.1",
29+
"@trpc/client": "^11.2.0",
30+
"@trpc/next": "^11.2.0",
31+
"@trpc/react-query": "^11.2.0",
32+
"@trpc/server": "^11.2.0",
3333
"app": "workspace:*",
3434
"expo-sharing": "13.0.1",
3535
"next": "15.3.1",
@@ -45,7 +45,7 @@
4545
"zod": "^3.23.8"
4646
},
4747
"devDependencies": {
48-
"@jest/globals": "^29.7.0",
48+
"@jest/globals": "^29",
4949
"@next/bundle-analyzer": "^13.4.19",
5050
"@next/eslint-plugin-next": "^14.0.4",
5151
"@tamagui/next-plugin": "^1.126.1",
@@ -54,7 +54,7 @@
5454
"@types/node": "^20",
5555
"dotenv-cli": "^7.3.0",
5656
"eslint-config-next": "^14.0.4",
57-
"jest": "^29.7.0",
57+
"jest": "^29",
5858
"jest-environment-jsdom": "^29.7.0"
5959
}
6060
}

docs/main-sendtag-approach.md

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Sendtags System: Complete Guide
2+
3+
## What Are Sendtags?
4+
5+
**Sendtags** (also called "tags") are unique usernames in the Send app that serve as human-readable identifiers for users. Think of them as "/handles" similar to Twitter usernames, but for cryptocurrency payments and social features. Users can send money to each other using sendtags instead of long wallet addresses.
6+
7+
### Key Characteristics
8+
- **Unique**: Each sendtag is globally unique across the Send app
9+
- **User-friendly**: Alphanumeric strings (1-20 characters, A-Z, a-z, 0-9, underscore)
10+
- **Payment identifiers**: Send money using "/alice" instead of wallet addresses
11+
- **Social identity**: Appear in activity feeds, profiles, and social interactions
12+
- **Multiple per user**: Each user can own up to 5 sendtags under their Send account
13+
- **Main tag**: Users designate one confirmed tag as their primary identity
14+
15+
### Example Use Cases
16+
- Sending money: "Send $10 to /alice"
17+
- Social features: "/bob liked your transaction"
18+
- Profile identity: Users choose a primary "main" sendtag for their public profile
19+
20+
## System Architecture
21+
22+
The sendtag system uses a three-table design that provides flexibility and proper data relationships:
23+
24+
### Core Tables
25+
1. **`tags`** - Stores the actual sendtag data (name, status, timestamps)
26+
2. **`send_account_tags`** - Junction table linking users' send accounts to their tags
27+
3. **`send_accounts`** - User accounts with a reference to their main tag
28+
29+
### Relationship Model
30+
```
31+
User → Send Account → Send Account Tags → Tags
32+
↑ ↑
33+
└─── main_tag_id ──────────────────┘
34+
```
35+
36+
This design allows:
37+
- Users to own multiple tags through the junction table
38+
- Easy addition/removal of tag associations
39+
- Automatic tag recycling when users release tags
40+
- Clean separation between tag ownership and tag existence
41+
42+
## Tag Status Lifecycle
43+
44+
Each tag has a status that controls its availability and usage:
45+
46+
### Status Types
47+
- **`pending`** - Tag claimed but payment not confirmed (30-minute expiration)
48+
- **`confirmed`** - Tag paid for and verified on blockchain
49+
- **`available`** - Previously owned tag that was released for reuse
50+
51+
### Lifecycle Flow
52+
1. **Creation**: User claims a tag → status becomes `pending`
53+
2. **Payment**: User pays and transaction is verified → status becomes `confirmed`
54+
3. **Usage**: Only `confirmed` tags can be used for payments and set as main tag
55+
4. **Release**: User deletes tag association → status becomes `available` (if no other owners)
56+
5. **Recycling**: Another user can claim `available` tags
57+
58+
### Business Rules
59+
- Users can own maximum 5 tags at once
60+
- Only confirmed tags work for payments and social features
61+
- Pending tags expire after 30 minutes without payment
62+
- Tag names are globally unique (case-insensitive)
63+
- Available tags preserve their name but clear ownership
64+
65+
## Security Model
66+
67+
The system uses PostgreSQL Row Level Security (RLS) to ensure data privacy and integrity:
68+
69+
### Tag Visibility
70+
- Users can only see tags they own through the junction table relationship
71+
- Anonymous users cannot see any private tag data
72+
- Confirmed tags may appear in public search results
73+
74+
### Tag Operations
75+
- **Creation**: Users can only create tags for their own send accounts
76+
- **Updates**: Users can only modify their own pending tags
77+
- **Deletion**: Two-tier system - pending tags can be deleted directly, confirmed tags must be released through the junction table
78+
79+
### Data Integrity
80+
- Foreign key constraints prevent orphaned references
81+
- Triggers automatically manage main tag assignment and succession
82+
- Business logic enforced at database level prevents invalid states
83+
84+
## Main Tag Feature
85+
86+
The main tag system designates one confirmed tag as a user's primary identity:
87+
88+
### Automatic Assignment
89+
- When a user's first tag is confirmed, it automatically becomes their main tag
90+
- No manual intervention required for basic functionality
91+
- Ensures all users with confirmed tags have a main tag
92+
93+
### Manual Selection
94+
- Users can change their main tag to any of their confirmed tags
95+
- Only confirmed tags are eligible to be main tags
96+
- Changes take effect immediately
97+
98+
### Succession Logic
99+
- If a user's main tag is deleted, the system automatically promotes their next oldest confirmed tag
100+
- If no other confirmed tags exist, main_tag_id is set to NULL
101+
- Prevents users from being left without a main tag when they have other options
102+
103+
## Key Operations
104+
105+
### Tag Creation
106+
When users create a new tag:
107+
1. System checks if an `available` tag with that name exists and claims it
108+
2. If no available tag exists, creates a new tag record
109+
3. Creates association in `send_account_tags` junction table
110+
4. Enforces 5-tag limit per user
111+
5. New tag starts in `pending` status
112+
113+
### Tag Confirmation
114+
When payment is verified:
115+
1. Backend verifies blockchain transaction receipt
116+
2. Updates tag status from `pending` to `confirmed`
117+
3. Creates activity feed entries
118+
4. Links to payment receipt for audit trail
119+
5. If this is user's first confirmed tag, automatically sets as main tag
120+
121+
### Tag Release
122+
Users can release tags in two ways:
123+
1. **Cancel pending tags**: Direct deletion removes unpaid reservations
124+
2. **Release confirmed tags**: Deleting from junction table releases ownership
125+
- If no other users own the tag, it becomes `available` for others
126+
- If it was the main tag, system automatically assigns new main tag
127+
- Tag name is preserved for potential reuse
128+
129+
## Integration Points
130+
131+
### Activity Feed
132+
- Tag confirmation creates activity entries visible to user's network
133+
- Tag operations include relevant metadata (transaction hashes, timestamps)
134+
- Social features use confirmed tags for user identification
135+
136+
### Payment System
137+
- Confirmed tags serve as payment identifiers in send flows
138+
- Receipt system links tag confirmations to blockchain transactions
139+
- Payment validation prevents unauthorized tag confirmations
140+
141+
### Search Functionality
142+
- Global search includes confirmed tags with fuzzy matching
143+
- Search results respect user privacy settings
144+
- Trigram indexing provides fast partial name matching
145+
146+
### Referral System
147+
- Tag confirmation can establish referral relationships
148+
- First tag registration may include referral codes
149+
- Referral tracking contributes to user rewards and verification
150+
151+
## For Developers
152+
153+
### API Patterns
154+
Most tag operations work through existing endpoints with automatic main tag handling. Only one new endpoint is needed:
155+
156+
```typescript
157+
// Update main tag (only new API needed)
158+
PUT /api/send-accounts/{id}
159+
{ main_tag_id: tagId }
160+
161+
// Existing patterns continue to work:
162+
POST /api/tags - creates tag, auto-assigns main if first
163+
DELETE /api/send-account-tags/{id} - releases tag, auto-reassigns main if needed
164+
```
165+
166+
### Query Patterns
167+
```typescript
168+
// Get user's tags with main tag indicator
169+
const tags = await supabase
170+
.from('tags')
171+
.select(`
172+
*,
173+
is_main:send_accounts!inner(main_tag_id)
174+
`)
175+
.eq('send_accounts.user_id', userId)
176+
```
177+
178+
### Key Constraints
179+
- Tag names: 1-20 characters, alphanumeric + underscore only
180+
- User limit: 5 active tags maximum
181+
- Main tag: Must be one of user's confirmed tags
182+
- Case sensitivity: Tag names are case-insensitive (stored as citext)
183+
- Uniqueness: Tag names are globally unique
184+
185+
### Migration Considerations
186+
For existing users, run migration to assign main tags:
187+
- Sets main_tag_id to user's oldest confirmed tag
188+
- New users get automatic assignment via triggers
189+
- No breaking changes to existing APIs
190+
191+
### Testing Requirements
192+
The system includes comprehensive test coverage for:
193+
- Tag creation and confirmation flows with payment verification
194+
- Main tag assignment and succession logic
195+
- RLS policies ensuring proper data isolation
196+
- Business rule enforcement (limits, validation, uniqueness)
197+
- Integration with activity feeds and receipt systems
198+
199+
This architecture provides a robust, scalable foundation for the sendtag system while maintaining simplicity for developers and users.

0 commit comments

Comments
 (0)