User Profile System Documentation
Overview
The User Profile system provides a Facebook-like profile structure for users, allowing them to showcase their fishing equipment, setups, catches, and custom 3D models. The system includes granular privacy controls for different profile sections.
Core Entities
UserProfile
Extended profile information for users, similar to Facebook profiles:
Profile Visibility Settings:
ProfileVisibility: Overall profile visibility (Public, Circle, Private)- Section-specific visibility:
BoatsVisibility: Who can see user's boatsGearSetupsVisibility: Who can see gear setupsFishingLogsVisibility: Who can see fishing logsAchievementsVisibility: Who can see achievementsPhotosVisibility: Who can see photosStatisticsVisibility: Who can see statistics
Profile Bio/About:
Bio: Short bio/about meLocation: Primary location (e.g., "Lake Michigan, Michigan")HomeWater: Primary fishing locationFavoriteSpecies: Comma-separated or JSONFishingStyle: e.g., "Trolling", "Casting", "Fly Fishing"YearsFishing: Years of fishing experience
Featured Content:
FeaturedBoatId: Featured boat on profileFeaturedGearSetupId: Featured gear setupFeaturedCatchId: Featured catch/photo
Profile Statistics (cached for performance):
TotalBoats,TotalGearSetups,TotalCatches,TotalFishingSessionsLargestCatchLbs,LongestCatchInchesFavoriteSpeciesName: Most caught speciesFollowerCount,FollowingCount,FriendCount
UserDefinedModel
User-created custom 3D models stored in their profile:
Model Data:
ModelUrl: URL to uploaded model (S3, etc.)ModelJson: Embedded JSON model dataModelDataBase64: Base64 encoded modelFormat: GLTF, GLB, JSON, etc.
Reference Dimensions:
ReferenceLengthFt,ReferenceWidthFt,ReferenceHeightFt,ReferenceDiameterInches- Used for scaling calculations
Links:
BaseModelId: Link to base model if this is a customizationBoatId,RodId,ReelId,BoatEquipmentId: Links to actual equipment
Visibility/Sharing:
Visibility: Public, Circle, or PrivateIsShared: Can be used by other usersIsFeatured: Featured on user's profileDownloadCount,LikeCount: Social metrics
Profile Visibility Levels
ProfileVisibility Enum
- Public: Anyone can view
- Circle: Only friends/circle members can view
- Private: Only the user can view
Usage Examples
Creating a User Profile
var profile = new UserProfile
{
UserId = userId,
ProfileVisibility = ProfileVisibility.Public,
BoatsVisibility = ProfileVisibility.Public,
GearSetupsVisibility = ProfileVisibility.Circle,
FishingLogsVisibility = ProfileVisibility.Public,
Bio = "Passionate Great Lakes salmon fisherman",
Location = "Lake Michigan, Michigan",
HomeWater = "Lake Michigan",
FavoriteSpecies = "Chinook Salmon, Coho Salmon, Steelhead",
FishingStyle = "Trolling",
YearsFishing = 15,
FeaturedBoatId = userBoatId,
FeaturedGearSetupId = userGearSetupId
};
context.UserProfiles.Add(profile);
context.SaveChanges();
Adding a User-Defined Model
var customModel = new UserDefinedModel
{
UserId = userId,
UserProfileId = userProfileId,
Name = "My Custom 22ft Center Console",
Description = "Custom 3D model of my boat",
ModelType = ModelType.Boat,
ModelUrl = "https://s3.amazonaws.com/models/user-boat.glb",
Format = ModelFormat.Glb,
ReferenceLengthFt = 22.0f,
ReferenceWidthFt = 8.5f,
ReferenceHeightFt = 3.2f,
BoatId = userBoatId, // Link to actual boat
Visibility = ProfileVisibility.Public,
IsShared = true, // Allow others to use
IsFeatured = true // Show on profile
};
context.UserDefinedModels.Add(customModel);
context.SaveChanges();
Querying Profile with Privacy Checks
// Get user profile with privacy check
var viewerId = currentUserId;
var profileUserId = targetUserId;
var profile = context.UserProfiles
.Include(up => up.User)
.Include(up => up.FeaturedBoat)
.Include(up => up.FeaturedGearSetup)
.Include(up => up.UserDefinedModels.Where(udm =>
udm.Visibility == ProfileVisibility.Public ||
(udm.Visibility == ProfileVisibility.Circle && IsFriend(viewerId, profileUserId))
))
.FirstOrDefault(up => up.UserId == profileUserId);
// Check if viewer can see profile
bool canView = profile.ProfileVisibility == ProfileVisibility.Public ||
(profile.ProfileVisibility == ProfileVisibility.Circle && IsFriend(viewerId, profileUserId)) ||
viewerId == profileUserId;
if (!canView)
{
return null; // Profile is private
}
// Filter boats based on visibility
var boats = context.Boats
.Where(b => b.UserId == profileUserId)
.ToList()
.Where(b => CanViewSection(profile.BoatsVisibility, viewerId, profileUserId))
.ToList();
Updating Profile Statistics
// Update cached statistics (can be done via background job)
var profile = context.UserProfiles.FirstOrDefault(up => up.UserId == userId);
profile.TotalBoats = context.Boats.Count(b => b.UserId == userId);
profile.TotalGearSetups = context.GearSetups.Count(gs => gs.UserId == userId);
profile.TotalCatches = context.FishingLogEntries
.Count(fle => fle.UserId == userId && fle.CatchDetails.Any());
profile.TotalFishingSessions = context.FishingSessions.Count(fs => fs.UserId == userId);
var largestCatch = context.CatchDetails
.Where(cd => cd.FishingLogEntry.UserId == userId)
.OrderByDescending(cd => cd.WeightKg)
.FirstOrDefault();
profile.LargestCatchLbs = largestCatch?.WeightKg * 2.20462f; // Convert to lbs
var favoriteSpecies = context.CatchDetails
.Where(cd => cd.FishingLogEntry.UserId == userId)
.GroupBy(cd => cd.FishSpecies.CommonName)
.OrderByDescending(g => g.Count())
.FirstOrDefault();
profile.FavoriteSpeciesName = favoriteSpecies?.Key;
profile.FollowerCount = context.UserFollows.Count(uf => uf.FollowingId == userId);
profile.FollowingCount = context.UserFollows.Count(uf => uf.FollowerId == userId);
profile.FriendCount = context.UserFriends.Count(uf => uf.UserId == userId || uf.FriendId == userId);
context.SaveChanges();
Privacy & Visibility
Profile-Level Privacy
- Controls overall profile visibility
- Default: Public
Section-Level Privacy
- Granular control over each section
- Can override profile-level setting
- Example: Profile is Public, but Boats are Circle-only
User-Defined Models Privacy
- Each model has its own visibility setting
- Can be shared (
IsShared = true) for others to use - Can be featured (
IsFeatured = true) on profile
Integration with Existing Entities
Boats
- Boats are linked to
User(already exists) - Can be featured on
UserProfileviaFeaturedBoatId - Visibility controlled by
UserProfile.BoatsVisibility
Gear Setups
- Gear setups are linked to
User(already exists) - Can be featured on
UserProfileviaFeaturedGearSetupId - Visibility controlled by
UserProfile.GearSetupsVisibility
Fishing Logs
- Fishing logs are linked to
User(already exists) - Can be featured on
UserProfileviaFeaturedCatchId - Visibility controlled by
UserProfile.FishingLogsVisibility
User-Defined Models
- Stored in
UserProfile.UserDefinedModels - Can link to actual equipment (
BoatId,RodId,ReelId,BoatEquipmentId) - Can be based on base models (
BaseModelId)
Benefits
- Facebook-like Profile: Familiar structure for users
- Granular Privacy: Control visibility per section
- Featured Content: Highlight best equipment/catches
- Custom Models: Users can create and share 3D models
- Performance: Cached statistics for fast profile loading
- Social Metrics: Follower/following/friend counts
Future Enhancements
- Profile Customization: Custom themes, layouts
- Profile Badges: Achievement badges on profile
- Profile Verification: Verified angler badges
- Model Marketplace: Share and sell custom models
- Profile Analytics: View profile visit statistics