Packages

phoenix_kit

1.7.65
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules connections README.md
Raw

lib/modules/connections/README.md

# Connections Module - Social Relationships System
## Overview
The Connections module provides a complete social relationships system for PhoenixKit applications with two types of relationships:
1. **Follows** - One-way relationships (User A follows User B, no consent needed)
2. **Connections** - Two-way mutual relationships (both users must accept)
Plus **blocking** functionality to prevent unwanted interactions.
## Architecture
Each relationship type uses a **dual-table pattern**:
- **Main table**: Stores only the **current state** (one row per user pair)
- **History table**: Logs all **activity over time** for auditing and activity feeds
This design keeps the main tables lean and fast while preserving a complete audit trail.
## Terminology
- **Follow**: One-way, no consent required (like Twitter/Instagram)
- **Connection**: Two-way, requires acceptance from both parties (like LinkedIn)
- **Block**: Prevents all interaction (following, connecting, profile viewing)
---
## Database Schema
### Main Tables (Current State)
#### Table: `phoenix_kit_user_follows`
Stores only ACTIVE follows. Row is deleted when user unfollows.
| Column | Type | Description |
|--------|------|-------------|
| id | UUIDv7 | Primary key |
| follower_uuid | UUID | User who is following (FK to users.uuid) |
| followed_uuid | UUID | User being followed (FK to users.uuid) |
| inserted_at | naive_datetime | When follow was created |
**Indexes:** Unique on `(follower_uuid, followed_uuid)`, index on `followed_uuid`, index on `follower_uuid`
#### Table: `phoenix_kit_user_connections`
Stores only CURRENT connection state per user pair. Status is "pending" or "accepted" only.
Rejected connections are deleted (not stored as "rejected").
| Column | Type | Description |
|--------|------|-------------|
| id | UUIDv7 | Primary key |
| requester_uuid | UUID | User who initiated request (FK to users.uuid) |
| recipient_uuid | UUID | User who received request (FK to users.uuid) |
| status | string | "pending" or "accepted" |
| requested_at | naive_datetime | When request was sent |
| responded_at | naive_datetime | When recipient responded |
| inserted_at | naive_datetime | Created timestamp |
| updated_at | naive_datetime | Updated timestamp |
**Indexes:** Index on `(recipient_uuid, status)`, index on `(requester_uuid, status)`
#### Table: `phoenix_kit_user_blocks`
Stores only ACTIVE blocks. Row is deleted when user unblocks.
| Column | Type | Description |
|--------|------|-------------|
| id | UUIDv7 | Primary key |
| blocker_uuid | UUID | User who blocked (FK to users.uuid) |
| blocked_uuid | UUID | User who is blocked (FK to users.uuid) |
| reason | string | Optional reason (nullable) |
| inserted_at | naive_datetime | When block was created |
**Indexes:** Unique on `(blocker_uuid, blocked_uuid)`, index on `blocked_uuid`
---
### History Tables (Activity Log)
#### Table: `phoenix_kit_user_follows_history`
Logs all follow/unfollow events.
| Column | Type | Description |
|--------|------|-------------|
| id | UUIDv7 | Primary key |
| follower_uuid | UUID | User who performed action (FK to users.uuid) |
| followed_uuid | UUID | Target user (FK to users.uuid) |
| action | string | "follow" or "unfollow" |
| inserted_at | naive_datetime | When action occurred |
#### Table: `phoenix_kit_user_connections_history`
Logs all connection events.
| Column | Type | Description |
|--------|------|-------------|
| id | UUIDv7 | Primary key |
| user_a_uuid | UUID | First user (normalized: lower UUID) (FK to users.uuid) |
| user_b_uuid | UUID | Second user (normalized: higher UUID) (FK to users.uuid) |
| actor_uuid | UUID | User who performed this action (FK to users.uuid) |
| action | string | "requested", "accepted", "rejected", "removed" |
| inserted_at | naive_datetime | When action occurred |
#### Table: `phoenix_kit_user_blocks_history`
Logs all block/unblock events.
| Column | Type | Description |
|--------|------|-------------|
| id | UUIDv7 | Primary key |
| blocker_uuid | UUID | User who performed action (FK to users.uuid) |
| blocked_uuid | UUID | Target user (FK to users.uuid) |
| action | string | "block" or "unblock" |
| reason | string | Reason (for block action) |
| inserted_at | naive_datetime | When action occurred |
---
## Public API: `PhoenixKit.Modules.Connections`
**This is a PUBLIC API** - all functions are available to parent applications for use in their own views, components, and logic.
### Module Management
```elixir
PhoenixKit.Modules.Connections.enabled?()
PhoenixKit.Modules.Connections.enable_system()
PhoenixKit.Modules.Connections.disable_system()
PhoenixKit.Modules.Connections.get_config()
PhoenixKit.Modules.Connections.get_stats()
```
### Follows
```elixir
# Create/remove follows (automatically logs to history)
follow(follower, followed) # Create a follow relationship
unfollow(follower, followed) # Remove a follow relationship
# Query follows
following?(follower, followed) # Check if user A follows user B
list_followers(user) # Get all followers of a user
list_following(user) # Get all users a user follows
followers_count(user) # Count followers
following_count(user) # Count following
```
### Connections
```elixir
# Connection requests (automatically logs to history)
request_connection(requester, recipient) # Send connection request
accept_connection(connection_id) # Accept a pending request
reject_connection(connection_id) # Reject a pending request
remove_connection(user_a, user_b) # Remove existing connection
# Query connections
connected?(user_a, user_b) # Check if two users are connected
list_connections(user) # Get all connections for a user
list_pending_requests(user) # Get pending incoming requests
list_sent_requests(user) # Get pending outgoing requests
connections_count(user) # Count connections
pending_requests_count(user) # Count pending incoming requests
```
### Blocks
```elixir
# Create/remove blocks (automatically logs to history)
block(blocker, blocked) # Block a user
unblock(blocker, blocked) # Remove a block
# Query blocks
blocked?(blocker, blocked) # Check if user A blocked user B
blocked_by?(user, other) # Check if user is blocked by other
list_blocked(user) # Get all users blocked by a user
can_interact?(user_a, user_b) # Check if two users can interact
```
### Relationship Status (Convenience)
```elixir
# Get full relationship status between two users in one call
get_relationship(user_a, user_b)
# Returns:
%{
following: true/false, # A follows B
followed_by: true/false, # B follows A
connected: true/false, # mutual connection exists
connection_pending: :sent/:received/nil,
blocked: true/false, # A blocked B
blocked_by: true/false # B blocked A
}
```
---
## Usage Examples
### In a User Profile Page
```elixir
# Get relationship for rendering follow/connect buttons
alias PhoenixKit.Modules.Connections
relationship = Connections.get_relationship(current_user, profile_user)
# Display counts
followers = Connections.followers_count(profile_user)
following = Connections.following_count(profile_user)
connections = Connections.connections_count(profile_user)
```
### In a LiveView
```elixir
def handle_event("follow", %{"user_id" => user_id}, socket) do
target_user = get_user(user_id)
case Connections.follow(socket.assigns.current_user, target_user) do
{:ok, _follow} -> {:noreply, put_flash(socket, :info, "Now following!")}
{:error, reason} -> {:noreply, put_flash(socket, :error, reason)}
end
end
def handle_event("request_connection", %{"user_id" => user_id}, socket) do
target_user = get_user(user_id)
case Connections.request_connection(socket.assigns.current_user, target_user) do
{:ok, _connection} -> {:noreply, put_flash(socket, :info, "Connection request sent!")}
{:error, reason} -> {:noreply, put_flash(socket, :error, reason)}
end
end
```
---
## Business Rules
### Following
- Cannot follow yourself
- Cannot follow if blocked (either direction)
- Instant, no approval needed
### Connections
- Cannot connect with yourself
- Cannot connect if blocked
- Requires acceptance from recipient
- If A requests B while B has pending request to A → auto-accept both
### Blocking
- Blocking removes any existing follow/connection between the users
- Blocked user cannot follow, connect, or view profile
- Blocking is one-way (A blocks B doesn't mean B blocks A)
---
## File Structure
```
lib/modules/connections/
README.md # This documentation
connections.ex # Main context API
follow.ex # Follow schema
follow_history.ex # Follow history schema
connection.ex # Connection schema
connection_history.ex # Connection history schema
block.ex # Block schema
block_history.ex # Block history schema
lib/phoenix_kit_web/live/modules/connections/
connections.ex # Admin: overview/moderation
connections.html.heex
user_connections.ex # User: manage own connections
user_connections.html.heex
lib/phoenix_kit/migrations/postgres/
v36.ex # Migration for all connection tables
```
---
## Admin Interface
Available at `{prefix}/admin/connections`:
- Overview statistics (total follows, connections, pending, blocks)
- Module enable/disable toggle
- Relationship type explanations
- Public API documentation
## User Interface
Available at `{prefix}/profile/connections`:
- **Followers** tab - Users who follow you
- **Following** tab - Users you follow (with unfollow button)
- **Connections** tab - Mutual connections (with remove button)
- **Requests** tab - Pending incoming/outgoing requests (with accept/reject buttons)
- **Blocked** tab - Users you've blocked (with unblock button)