Linkarooie is a robust, open-source alternative to Linktree, built with Ruby on Rails. It provides a centralized platform for managing and sharing your important links, achievements, and online presence. Created as a replacement for the archived BioDrop (LinkFree) project, Linkarooie offers a feature-rich, customizable solution designed for easy deployment and management.
- Features
- Tech Stack
- Getting Started
- Docker Deployment
- DigitalOcean Deployment
- Configuration
- Backup and Restore Process
- Geolocation
- Customization
- Testing
- CI/CD
- Project Structure
- Key Components
- Gather Script
- Contributing
- License
- Support
- Acknowledgements
Lb0vjzCyZb.mp4
-
Custom Links Management:
- Add, edit, and delete links with titles, URLs, descriptions, and custom icons
- Toggle link visibility
- Pin important links to the top of your profile
- Organize links with custom positioning
-
User Profiles:
- Customizable profiles with avatars, banners, full names, usernames, and descriptions
- Tagging system for categorizing profiles
-
User Achievements:
- Create and showcase personal or professional accomplishments
- Include achievement titles, dates, descriptions, icons, and URLs
-
Analytics:
- Track page views, link clicks, and unique visitors
- View daily metrics for user engagement
- Geolocation tracking for visitor insights (currently mandatory)
-
Open Graph Image Generation:
- Automatic creation of social media preview images for improved sharing
-
Responsive Design:
- Ensures optimal user experience across all devices
-
Background Job Processing:
- Utilizes Sidekiq for efficient handling of background tasks
-
Asset Management:
- Implements Vite for modern, efficient frontend asset handling
-
Automated Backups:
- Daily backups to DigitalOcean Spaces with easy restoration process
-
Backend:
- Ruby 3.3.0 (local development)
- Ruby 3.3.4 (production Docker image)
- Rails 7.1.3
- SQLite3 (development)
- PostgreSQL/MySQL (recommended for production)
- Sidekiq for background job processing
- Redis for Sidekiq and caching
-
Frontend:
- Vite for asset compilation and management
- Tailwind CSS for styling
- Stimulus.js for JavaScript sprinkles
- Chartkick for chart generation
-
Testing:
- RSpec for unit and integration tests
- Factory Bot for test data generation
- Shoulda Matchers for additional RSpec matchers
-
Deployment & Infrastructure:
- Docker and Docker Compose for containerization
- GitHub Actions for CI/CD
- Terraform for infrastructure as code
- DigitalOcean for hosting (Droplets and Spaces)
-
Additional Libraries:
- Devise for authentication
- Geocoder for geolocation services
- AWS SDK for S3 compatible storage interactions
- Font Awesome for icons
- Ruby 3.3.0 or higher
- Rails 7.1.3 or higher
- SQLite3
- Node.js (v20 or higher) and npm
- Docker and Docker Compose (for containerized deployment)
- Git
-
Clone the repository:
git clone https://github.com/loftwah/linkarooie.git cd linkarooie
-
Install Ruby dependencies:
bundle install
-
Install JavaScript dependencies:
npm install
-
Set up the database:
rails db:create db:migrate db:seed
-
Start the development servers:
bin/dev
This command starts the Rails server, Vite dev server, and Tailwind CSS watcher.
-
Visit
http://localhost:3000
in your browser to access the application.
Linkarooie provides an interactive Ruby script for creating new users:
-
Run the script:
ruby create_user.rb
-
Follow the prompts to enter user details, including:
- Password
- Username (optional)
- Full name
- Tags (comma-separated)
- Avatar URL
- Banner URL
- Description
This script allows for easy user creation, especially useful for setting up initial accounts or testing.
Linkarooie uses Docker for easy deployment and scaling. The project includes a multi-stage Dockerfile for creating a lean production image.
-
Build and start the Docker containers:
docker compose -f docker-compose.prod.yml up --build
-
Access the application at
http://localhost
.
The production Docker setup includes:
- Rails application container
- Redis container for Sidekiq and caching
- Sidekiq container for background job processing
Key Dockerfile features:
- Multi-stage build for a smaller final image
- Precompilation of assets and bootsnap
- Non-root user for improved security
Linkarooie is optimized for deployment on DigitalOcean using Terraform for infrastructure management and GitHub Actions for continuous deployment.
-
Install Terraform and set up a DigitalOcean account.
-
Configure your DigitalOcean API token:
export DO_TOKEN=your_digitalocean_api_token
-
Create a DigitalOcean Droplet:
cd terraform/droplet terraform init terraform apply -var="do_token=$DO_TOKEN"
-
Set up DigitalOcean Spaces for backups:
cd ../spaces terraform init terraform apply
-
Set up the following secrets in your GitHub repository:
DROPLET_IP
: The IP address of your DigitalOcean Droplet (output from Terraform)DROPLET_SSH_PRIVATE_KEY
: The private SSH key to access your DropletGH_PAT
: Your GitHub Personal Access Token
-
The GitHub Actions workflows will automatically:
- Run tests and build Docker images on pull requests and pushes to feature branches
- Deploy to your DigitalOcean Droplet when changes are merged to the main branch
You can also trigger a manual deployment using the GitHub Actions workflow dispatch event.
Create a .env
file in the root directory with the following variables:
SECRET_KEY_BASE=your_secret_key_base
AXIOM_API_KEY=your_axiom_api_key
DO_TOKEN=your_digitalocean_token
SPACES_ACCESS_KEY_ID=your_spaces_access_key_id
SPACES_SECRET_ACCESS_KEY=your_spaces_secret_access_key
SPACES_REGION=your_spaces_region
SPACES_BUCKET_NAME=your_spaces_bucket_name
RAILS_ENV=production
CACHE_EXPIRATION=30
Ensure all placeholder values are replaced with your actual API keys and tokens.
- Development and test environments use SQLite3.
- For production, configure your preferred database (PostgreSQL recommended) in
config/database.yml
.
Linkarooie includes an automated backup system utilizing DigitalOcean Spaces:
- The
BackupDatabaseJob
runs daily at 2 AM. - It creates a dump of the SQLite database and uploads it to a DigitalOcean Spaces bucket.
- Backups are versioned for easy point-in-time recovery.
Use the provided Rake task to restore from a backup:
rake db:restore BACKUP_FILE=path/to/your_backup_file.sql
For compressed backups:
rake db:restore BACKUP_FILE=path/to/your_backup_file.sql.tar.gz
The restore process:
- Drops all existing tables in the database.
- Loads the specified backup file.
- Applies any pending migrations.
Linkarooie is designed to be highly customizable:
- Views: Modify ERB templates in
app/views/
- Styles:
- Edit Tailwind CSS classes directly in views
- Customize Tailwind configuration in
config/tailwind.config.js
- Add custom styles in
app/assets/stylesheets/application.css.scss
- JavaScript:
- Add or modify Stimulus controllers in
app/javascript/controllers/
- Update the main JavaScript file at
app/javascript/application.js
- Add or modify Stimulus controllers in
- Backend Logic:
- Controllers are located in
app/controllers/
- Models are in
app/models/
- Controllers are located in
- Background Jobs: Add or modify Sidekiq jobs in
app/jobs/
- Localization: Update language files in
config/locales/
Linkarooie uses RSpec for testing. The test suite includes:
- Model specs
- Controller specs
- Feature specs
- Helper specs
To run the entire test suite:
bundle exec rspec
To run specific tests:
bundle exec rspec spec/models
bundle exec rspec spec/controllers
bundle exec rspec spec/features
Linkarooie utilizes GitHub Actions for continuous integration and deployment:
-
CI Workflow (
ci.yml
):- Triggered on pull requests to
main
and pushes to feature branches - Sets up Ruby and Node.js environments
- Installs dependencies
- Runs tests
- Builds and pushes Docker image to GitHub Container Registry
- Triggered on pull requests to
-
Deployment Workflow (
deploy.yml
):- Triggered on merges to
main
or manual dispatch - Builds and pushes Docker image
- SSHs into the DigitalOcean Droplet
- Pulls the latest Docker image
- Runs database migrations
- Restarts the application containers
- Triggered on merges to
linkarooie/
├── app/
│ ├── assets/
│ ├── controllers/
│ ├── helpers/
│ ├── javascript/
│ ├── jobs/
│ ├── mailers/
│ ├── models/
│ ├── services/
│ └── views/
├── bin/
├── config/
├── db/
├── lib/
├── public/
├── spec/
├── storage/
├── terraform/
│ ├── droplet/
│ └── spaces/
├── .github/workflows/
├── Dockerfile
├── docker-compose.prod.yml
├── Gemfile
├── package.json
└── ...
- User Model: Manages user accounts, profiles, and authentication.
- Link Model: Handles the creation and management of user links.
- Achievement Model: Manages user achievements and milestones.
- Analytics: Tracks and stores user engagement metrics.
- OpenGraphImageGenerator: Service for creating social media preview images.
- BackupDatabaseJob: Manages automated database backups.
- GRABIT.SH was inspired by this script.
The gather.sh
script is a utility for collecting project information:
./gather.sh [-o output_method] [-f output_file]
-o, --output Output method: stdout, clipboard, or file (default: stdout)
-f, --file Output file path (required if output method is file)
Note: There is also a
gather.rb
that works the same.
This script is useful for quickly compiling project details for documentation or sharing.
-
Create a User:
User.create!( email: "[email protected]", password: "Password123", username: "newuser", full_name: "New User", tags: ["Tech", "Music"].to_json, # Tags as JSON array avatar: "https://example.com/avatar.png", avatar_border: "white", banner: "https://example.com/banner.png", description: "User description", community_opt_in: true, public_analytics: true )
-
List Users:
User.pluck(:email, :username, :full_name)
-
Find and Update a User:
user = User.find_by(email: "[email protected]") user.update!(full_name: "Updated Name")
-
Delete a User:
user = User.find_by(email: "[email protected]") user.destroy!
-
List All Links for a User:
user = User.find_by(username: "newuser") user.links.pluck(:title, :url, :pinned, :position)
-
Create a Link:
user = User.find_by(username: "newuser") user.links.create!(title: "GitHub", url: "https://github.com", icon: "fa-brands fa-github")
-
Delete a Link:
link = Link.find_by(url: "https://github.com") link.destroy!
-
List Achievements for a User:
user = User.find_by(username: "newuser") user.achievements.pluck(:title, :date, :description, :url)
-
Create an Achievement:
user = User.find_by(username: "newuser") user.achievements.create!(title: "Achievement", date: Date.today, description: "Details")
-
Delete an Achievement:
achievement = Achievement.find_by(title: "Achievement") achievement.destroy!
-
View Total Page Views for a User:
user = User.find_by(username: "newuser") user.page_views.count
-
View Detailed Page Views:
user = User.find_by(username: "newuser") user.page_views.pluck(:path, :visited_at, :referrer, :browser)
-
Get Unique Visitors for a User:
user = User.find_by(username: "newuser") user.page_views.distinct.count(:ip_address)
-
Export Users to CSV:
require 'csv' CSV.open("users.csv", "wb") do |csv| csv << ["Email", "Username", "Full Name", "Tags"] User.all.each do |user| csv << [user.email, user.username, user.full_name, JSON.parse(user.tags).join(", ")] end end
-
Import Users from CSV:
require 'csv' CSV.foreach("path_to_users.csv", headers: true) do |row| User.create!( email: row["Email"], username: row["Username"], full_name: row["Full Name"], tags: row["Tags"].split(',').to_json, password: "Password123", password_confirmation: "Password123" ) end
-
Users Without Achievements:
User.left_joins(:achievements).where(achievements: { id: nil }).pluck(:username, :email)
-
Users with Public Analytics Enabled:
User.where(public_analytics: true).pluck(:username, :email)
We welcome contributions to Linkarooie! Here's how you can help:
- Fork the repository
- Create your feature branch:
git checkout -b feature/AmazingFeature
- Commit your changes:
git commit -m 'Add some AmazingFeature'
- Push to the branch:
git push origin feature/AmazingFeature
- Open a Pull Request
Please ensure your code adheres to the existing style and passes all tests.
This project is licensed under the MIT License - see the LICENSE file for details.
If you find Linkarooie helpful, please consider:
- Starring the repository on GitHub
- Sharing the project with others
- Contributing to the codebase
- Reporting issues or suggesting improvements
Linkarooie © 2024 - Simplify Your Online Presence