Identity & Members
Profiles Service
The Profiles service manages user profiles in the biztechProfiles DynamoDB table. Profiles are created during membership grant or manually via POST /profiles. Handlers are in services/profiles/handler.js.
Endpoints
| Method | Path | Auth | Handler | Description |
|---|---|---|---|---|
POST | /profiles | Cognito | create | Create profile for current user |
GET | /profiles/profile/{profileID} | Public | getPublicProfile | Get public-facing profile |
GET | /profiles/user/ | Cognito | getUserProfile | Get current user's full profile |
PATCH | /profiles/user/ | Cognito | updatePublicProfile | Update profile fields / visibility |
POST | /profiles/profile-pic-upload-url | Cognito | createProfilePicUploadUrl | Get presigned S3 upload URL |
Deprecated endpoints
These exist in the handler but are no longer part of the core product flow:
| Method | Path | Handler | Description |
|---|---|---|---|
POST | /profiles/partner/partial | createPartialPartnerProfile | Create partner profile + NFC |
POST | /profiles/company | createCompanyProfile | Create company profile + QR |
POST | /profiles/company/link-partner | linkPartnerToCompany | Link partner to a company |
POST | /profiles/sync-partner-data | syncPartnerData | Bulk sync partner profiles |
Table Structure
Table: biztechProfiles (constant PROFILES_TABLE). Composite key:
| Key | Attribute | Value |
|---|---|---|
| PK | compositeID | PROFILE#<profileID> where profileID is a human-readable ID |
| SK | type | PROFILE for profile records, CONNECTION#<id> for connection records |
The profileID is generated by the human-id library (e.g. SillyPandasDeny). Connection records share this table — see Connections for details.
Profile Types
The profileType field is set at creation:
| Type | Assigned when |
|---|---|
EXEC | Creator's email ends with @ubcbiztech.com |
ATTENDEE | All other users |
PARTNER | Set via deprecated createPartialPartnerProfile endpoint |
POST /profiles — Create Profile
Creates a profile for the authenticated user. Uses the email from the Cognito JWT claims.
Behavior:
- Looks up the user in
biztechMembers2026by email - Generates a
profileIDusinghuman-id - Creates a profile record with default
viewableMap(all optional fields hidden) - Updates the member record with a link to the new profile
No request body is needed — fname, lname, pronouns, year, major are read from the member record.
Automatic creation
Profiles are also created automatically during membership grant (POST /members/grant) and during payment webhook processing. Direct POST /profiles is mainly needed for exec self-enrollment.
GET /profiles/profile/{profileID} — Public Profile
Returns only the profile fields the user has marked as visible in their viewableMap.
Always returned: profileType, fname, lname, pronouns, year, major
Conditionally returned (based on viewableMap):
hobby1,hobby2funQuestion1,funQuestion2linkedInprofilePictureURLadditionalLinkdescription
No authentication required. This is the endpoint used to display profiles on the companion app and live wall.
GET /profiles/user/ — Full Profile
Returns the complete profile for the authenticated user, including all fields and the viewableMap. Requires Cognito auth.
The response includes every field on the profile record:
{
"profileType": "ATTENDEE",
"fname": "Kevin",
"lname": "Xiao",
"pronouns": "He/Him",
"year": "3rd Year",
"major": "BUCS",
"hobby1": "",
"hobby2": "",
"funQuestion1": "",
"funQuestion2": "",
"linkedIn": "",
"profilePictureURL": "",
"additionalLink": "",
"description": "",
"viewableMap": {
"fname": true,
"lname": true,
"pronouns": true,
"year": true,
"major": true,
"hobby1": false,
"hobby2": false,
"funQuestion1": false,
"funQuestion2": false,
"linkedIn": false,
"profilePictureURL": false,
"additionalLink": false,
"description": false
},
"compositeID": "PROFILE#SillyPandasDeny",
"type": "PROFILE",
"createdAt": 1754072664036,
"updatedAt": 1754072664036
}
PATCH /profiles/user/ — Update Profile
Updates mutable profile attributes and/or visibility settings. Requires Cognito auth.
Mutable attributes (defined in MUTABLE_PROFILE_ATTRIBUTES): hobby1, hobby2, funQuestion1, funQuestion2, linkedIn, profilePictureURL, additionalLink, description
Fields like fname, lname, pronouns, year, major are not updatable through this endpoint — they come from the member record.
Request body:
{
"viewableMap": { "description": true },
"description": "Testing description"
}
The viewableMap field is required in the body (at minimum an empty object {}). Only the keys you include will be updated — omitted keys keep their current values.
POST /profiles/profile-pic-upload-url — Profile Picture Upload
Generates a presigned S3 URL for uploading a profile picture. Requires Cognito auth.
Request body:
| Field | Required | Description |
|---|---|---|
fileType | Yes | MIME type (must start with image/) |
fileName | Yes | Original file name |
prefix | No | Subfolder prefix (defaults to profile-photos) |
Optionally pass profileId as a query parameter — if omitted, uses the authenticated user's profile.
Response:
{
"uploadUrl": "https://s3...presigned-url",
"key": "profile-pictures/SillyPandasDeny/profile-photos/1735689600000.jpg",
"publicUrl": "https://bucket.s3.region.amazonaws.com/profile-pictures/..."
}
The presigned URL expires after 60 seconds.
Key Files
| File | Purpose |
|---|---|
services/profiles/handler.js | All endpoint handlers |
services/profiles/helpers.js | createProfile, filterPublicProfileFields, buildProfileUpdateParams |
services/profiles/constants.js | MUTABLE_PROFILE_ATTRIBUTES, PROFILE_TYPES, TYPES |
Related Pages
- User, Member & Profile Relationships — how profiles connect to users and members
- Membership Flow — how profiles are created during membership grant
- Connections — connection records that share the profiles table