mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-20 23:06:41 +02:00
Move inactive projects out of active workspace: - bauntown (community website) - maerchenzauber (AI story generation) - memoro (voice memo app) - news (news aggregation) - nutriphi (nutrition tracking) - reader (reading app) - uload (URL shortener) - wisekeep (AI wisdom extraction) Update CLAUDE.md documentation: - Add presi to active projects - Document archived projects section - Update workspace configuration Archived apps can be re-activated by moving back to apps/ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
320 lines
11 KiB
Markdown
320 lines
11 KiB
Markdown
# Character Sharing Feature - Implementation Complete
|
|
|
|
## Overview
|
|
|
|
Users can now share **private characters** with friends via deep links. Characters remain private to the owner, but anyone with the link can import them to their library for 10 credits.
|
|
|
|
**Key Concept:** This is **private sharing** - no publishing required. Your character stays private, only people with the link can see and import it.
|
|
|
|
## Important: Private Sharing Model
|
|
|
|
Unlike typical social features, this implementation prioritizes **privacy**:
|
|
|
|
- ✅ **No Publishing Required** - Share any character instantly
|
|
- ✅ **Stays Private** - Your character remains yours, not in public galleries
|
|
- ✅ **Link-Only Access** - Only people with the deep link can view/import
|
|
- ✅ **Full Control** - Delete the character = link stops working
|
|
- ❌ **No Public Discovery** - Characters aren't searchable or browsable
|
|
- ❌ **No Analytics** - You won't see who clicked your link (privacy-first)
|
|
|
|
**Use Case:** Share a character privately with a friend via Messages/WhatsApp, not publish to the world.
|
|
|
|
## What Was Implemented
|
|
|
|
### Backend Changes (NestJS)
|
|
|
|
1. **New DTO** (`backend/src/character/dto/import-character.dto.ts`)
|
|
- Validation for character import requests
|
|
|
|
2. **Service Methods** (`backend/src/core/services/supabase-jsonb-auth.service.ts`)
|
|
- `getSharedCharacter(characterId)` - Public endpoint to fetch **any** character by ID (private sharing)
|
|
- `importCharacter(characterId, userId, token)` - Creates a copy of shared character
|
|
- Includes validation for:
|
|
- User can't import their own characters
|
|
- User can't import same character twice
|
|
|
|
3. **Controller Endpoints** (`backend/src/character/character.controller.ts`)
|
|
- `GET /character/shared/:characterId` - Public endpoint (no auth required) - works with private characters
|
|
- `POST /character/import/:characterId` - Authenticated endpoint with credit check
|
|
- 10 credits required to import a character
|
|
- Tracks import metadata and increments `times_shared` counter
|
|
- **No publishing required** - characters stay private
|
|
|
|
### Mobile App Changes (React Native/Expo)
|
|
|
|
1. **Deep Linking Configuration**
|
|
- Updated `mobile/app.json` - Changed scheme from `"myapp"` to `"maerchenzauber"`
|
|
- Created `mobile/app/+native-intent.tsx` - Deep link handler
|
|
- Handles URLs: `maerchenzauber://share/character/{characterId}`
|
|
|
|
2. **Character Preview Screen** (`mobile/app/character/preview/[characterId].tsx`)
|
|
- Displays shared character details
|
|
- Shows all character images with selector
|
|
- Import button with credit requirement displayed
|
|
- Prevents importing own characters
|
|
- Prevents duplicate imports
|
|
|
|
3. **Share Button Component** (`mobile/components/character/ShareCharacterButton.tsx`)
|
|
- Simple "Share Character" button
|
|
- Native share dialog integration
|
|
- **No publishing required** - direct private sharing
|
|
- Generates deep link and opens native share sheet
|
|
|
|
4. **Integration** (`mobile/app/character/[id].tsx`)
|
|
- Added ShareCharacterButton to character detail screen
|
|
- Positioned below character name/sharing status
|
|
|
|
## Database Schema Requirements
|
|
|
|
The following fields should exist in the `characters` table:
|
|
|
|
```sql
|
|
-- Existing fields (already in use):
|
|
- id (uuid)
|
|
- user_id (uuid)
|
|
- name (text)
|
|
- image_url (text)
|
|
- images_data (jsonb)
|
|
- user_description (text)
|
|
- character_description (text)
|
|
- character_description_prompt (text)
|
|
- is_animal (boolean)
|
|
- animal_type (text)
|
|
- blur_hash (text)
|
|
-- Publishing fields (optional - not used in private sharing):
|
|
- is_published (boolean) -- Can remain, but not required for sharing
|
|
- sharing_preference (text) -- Can remain, but not used in this implementation
|
|
- share_code (text) -- Can remain, but not used in this implementation
|
|
- published_at (timestamp) -- Can remain, but not used in this implementation
|
|
|
|
-- Existing field (already in database):
|
|
- cloned_from (uuid) -- References id of original character (used for imports)
|
|
|
|
-- New fields added by migration:
|
|
- imported_from_user_id (text) -- User ID of original creator
|
|
- imported_at (timestamptz) -- When character was imported
|
|
- times_shared (integer) -- Counter for how many times character was imported (default: 0)
|
|
```
|
|
|
|
### Migration Applied ✅
|
|
|
|
The migration has been applied to your database. The following fields were added:
|
|
|
|
- `imported_from_user_id` (text)
|
|
- `imported_at` (timestamptz)
|
|
- `times_shared` (integer, default 0)
|
|
|
|
And we're using the existing `cloned_from` field to track the original character.
|
|
|
|
## Testing Guide
|
|
|
|
### Setup
|
|
|
|
1. **Restart Backend**: `cd backend && npm run dev`
|
|
2. **Restart Mobile App with Cache Clear**: `cd mobile && npx expo start -c`
|
|
- Important: Use `-c` flag to clear cache after app.json scheme change
|
|
|
|
### Test Scenario 1: Private Sharing (Simplified)
|
|
|
|
1. **Login as User A**
|
|
2. **Navigate to any character you created** (doesn't need to be published)
|
|
3. **Tap "Share Character" button**
|
|
- Native share dialog appears immediately
|
|
- No publishing modal required
|
|
4. **Share dialog shows**:
|
|
- Share link format: `maerchenzauber://share/character/{characterId}`
|
|
- Share via any method (Messages, WhatsApp, Email, Copy Link)
|
|
- Send link to yourself or another device for testing
|
|
|
|
### Test Scenario 2: Receiving and Importing
|
|
|
|
1. **Login as User B** (different account)
|
|
2. **Open the shared link**
|
|
- Tap the deep link you shared
|
|
- App should open to character preview screen
|
|
3. **Preview screen should show**:
|
|
- Character images (with image selector if multiple)
|
|
- Character name and description
|
|
- Animal type badge (if applicable)
|
|
- "Import to My Library (10 Credits)" button
|
|
4. **Tap Import button**
|
|
- Confirm dialog should appear
|
|
- Should show "Import for 10 credits?"
|
|
- Tap confirm
|
|
5. **After successful import**:
|
|
- Success toast appears
|
|
- Navigate to imported character detail
|
|
- Character should be in User B's library
|
|
|
|
### Test Scenario 3: Edge Cases
|
|
|
|
1. **User tries to import their own character**
|
|
- Should show error: "Cannot import your own character"
|
|
|
|
2. **User tries to import same character twice**
|
|
- Should show error: "You have already imported this character"
|
|
|
|
3. **User with insufficient credits**
|
|
- Should show error: "You need 10 credits to import..."
|
|
|
|
4. **User tries to access deleted character**
|
|
- Deep link should show error: "Character not found"
|
|
|
|
### Test Scenario 4: Deep Link Testing
|
|
|
|
**Test deep link manually:**
|
|
|
|
```bash
|
|
# iOS
|
|
xcrun simctl openurl booted "maerchenzauber://share/character/YOUR_CHARACTER_ID"
|
|
|
|
# Android
|
|
adb shell am start -W -a android.intent.action.VIEW -d "maerchenzauber://share/character/YOUR_CHARACTER_ID"
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### Get Shared Character (Public)
|
|
|
|
```http
|
|
GET /character/shared/:characterId
|
|
```
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"id": "uuid",
|
|
"name": "Character Name",
|
|
"image_url": "https://...",
|
|
"images_data": [...],
|
|
"user_description": "...",
|
|
"is_animal": true,
|
|
"animal_type": "fox",
|
|
"user_id": "creator-uuid"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Import Character
|
|
|
|
```http
|
|
POST /character/import/:characterId
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"id": "new-uuid",
|
|
"name": "Character Name",
|
|
"imageUrl": "https://...",
|
|
...
|
|
},
|
|
"message": "Character imported successfully"
|
|
}
|
|
```
|
|
|
|
## Deep Link Format
|
|
|
|
```
|
|
maerchenzauber://share/character/{characterId}
|
|
```
|
|
|
|
**Example:**
|
|
|
|
```
|
|
maerchenzauber://share/character/a1b2c3d4-e5f6-7890-abcd-ef1234567890
|
|
```
|
|
|
|
## File Changes Summary
|
|
|
|
### New Files
|
|
|
|
1. `backend/src/character/dto/import-character.dto.ts`
|
|
2. `mobile/app/+native-intent.tsx`
|
|
3. `mobile/app/character/preview/[characterId].tsx`
|
|
4. `mobile/components/character/ShareCharacterButton.tsx`
|
|
5. `CHARACTER_SHARING_IMPLEMENTATION.md` (this file)
|
|
|
|
### Modified Files
|
|
|
|
1. `backend/src/core/services/supabase-jsonb-auth.service.ts`
|
|
2. `backend/src/character/character.controller.ts`
|
|
3. `mobile/app.json`
|
|
4. `mobile/app/character/[id].tsx`
|
|
|
|
## Known Limitations
|
|
|
|
1. **No web fallback** - Deep links only work when app is installed
|
|
2. **No share analytics** - Not tracking link opens or share sources
|
|
3. **No creator rewards** - Original creator doesn't receive credits when character is imported
|
|
4. **No QR codes** - Only URL-based sharing implemented
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Universal Links** - Add web landing page for users without app
|
|
2. **Share Analytics** - Track how many times links are clicked
|
|
3. **Creator Rewards** - Give original creator 5 credits when someone imports
|
|
4. **QR Code Generation** - Allow generating QR codes for in-person sharing
|
|
5. **Popular Characters Leaderboard** - Show most imported characters
|
|
6. **Share Templates** - Custom messages for different platforms
|
|
|
|
## Troubleshooting
|
|
|
|
### Deep Link Not Working
|
|
|
|
- Ensure you restarted Expo with `-c` flag after changing app.json
|
|
- Check that URL scheme is `maerchenzauber` (not `myapp`)
|
|
- On iOS, deep links might not work in simulator for some URLs - test on device
|
|
- On Android, ensure app is in foreground or background (not force-closed)
|
|
|
|
### Import Failing
|
|
|
|
- Check user has 10+ credits available
|
|
- Verify character is published (is_published = true)
|
|
- Check character sharing_preference is not 'private'
|
|
- Ensure user is not trying to import their own character
|
|
|
|
### Backend Errors
|
|
|
|
- Check Supabase RLS policies allow reading published characters
|
|
- Verify all new database fields exist in characters table
|
|
- Check backend logs for specific error messages
|
|
|
|
## Success Criteria
|
|
|
|
✅ User can share **any private character** directly (no publishing required)
|
|
✅ Share button opens native share dialog immediately
|
|
✅ Deep link opens app to character preview screen
|
|
✅ Character preview shows all character details
|
|
✅ Import button validates credits (10 required)
|
|
✅ Import creates new character copy in user's library
|
|
✅ Prevents self-import and duplicate imports
|
|
✅ Times_shared counter increments on original character
|
|
✅ Share button integrates seamlessly into character detail screen
|
|
✅ **Character remains private to owner** - only people with link can import
|
|
|
|
## Testing Checklist
|
|
|
|
- [ ] Backend endpoints return correct responses
|
|
- [ ] Deep links open app to preview screen
|
|
- [ ] Character preview displays all information (even for private characters)
|
|
- [ ] Import validates credits correctly
|
|
- [ ] Import creates character copy
|
|
- [ ] Prevents self-import
|
|
- [ ] Prevents duplicate import
|
|
- [ ] Share button works without publishing (private sharing)
|
|
- [ ] Share dialog shows correct deep link
|
|
- [ ] Credit deduction works (10 credits)
|
|
- [ ] Toast notifications appear correctly
|
|
- [ ] Error handling works for all edge cases
|
|
- [ ] Original character remains private after sharing
|
|
|
|
---
|
|
|
|
**Implementation Date:** 2025-10-31
|
|
**Status:** ✅ Complete - Ready for Testing
|