Skip to main content

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 boats
    • GearSetupsVisibility: Who can see gear setups
    • FishingLogsVisibility: Who can see fishing logs
    • AchievementsVisibility: Who can see achievements
    • PhotosVisibility: Who can see photos
    • StatisticsVisibility: Who can see statistics

Profile Bio/About:

  • Bio: Short bio/about me
  • Location: Primary location (e.g., "Lake Michigan, Michigan")
  • HomeWater: Primary fishing location
  • FavoriteSpecies: Comma-separated or JSON
  • FishingStyle: e.g., "Trolling", "Casting", "Fly Fishing"
  • YearsFishing: Years of fishing experience

Featured Content:

  • FeaturedBoatId: Featured boat on profile
  • FeaturedGearSetupId: Featured gear setup
  • FeaturedCatchId: Featured catch/photo

Profile Statistics (cached for performance):

  • TotalBoats, TotalGearSetups, TotalCatches, TotalFishingSessions
  • LargestCatchLbs, LongestCatchInches
  • FavoriteSpeciesName: Most caught species
  • FollowerCount, 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 data
  • ModelDataBase64: Base64 encoded model
  • Format: GLTF, GLB, JSON, etc.

Reference Dimensions:

  • ReferenceLengthFt, ReferenceWidthFt, ReferenceHeightFt, ReferenceDiameterInches
  • Used for scaling calculations

Links:

  • BaseModelId: Link to base model if this is a customization
  • BoatId, RodId, ReelId, BoatEquipmentId: Links to actual equipment

Visibility/Sharing:

  • Visibility: Public, Circle, or Private
  • IsShared: Can be used by other users
  • IsFeatured: Featured on user's profile
  • DownloadCount, 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 UserProfile via FeaturedBoatId
  • Visibility controlled by UserProfile.BoatsVisibility

Gear Setups

  • Gear setups are linked to User (already exists)
  • Can be featured on UserProfile via FeaturedGearSetupId
  • Visibility controlled by UserProfile.GearSetupsVisibility

Fishing Logs

  • Fishing logs are linked to User (already exists)
  • Can be featured on UserProfile via FeaturedCatchId
  • 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

  1. Facebook-like Profile: Familiar structure for users
  2. Granular Privacy: Control visibility per section
  3. Featured Content: Highlight best equipment/catches
  4. Custom Models: Users can create and share 3D models
  5. Performance: Cached statistics for fast profile loading
  6. Social Metrics: Follower/following/friend counts

Future Enhancements

  1. Profile Customization: Custom themes, layouts
  2. Profile Badges: Achievement badges on profile
  3. Profile Verification: Verified angler badges
  4. Model Marketplace: Share and sell custom models
  5. Profile Analytics: View profile visit statistics