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