# Recipes Pages

This book is a collection of code snippets, patterns, and guides to solving common problems in our projects. Please take a look through these to save yourself time when implementing certain features!

# Base README Template

This template should be used as a starting point for all Vegan Hacktivists projects.

```md
# [PROJECT_NAME](https://example.org)

1. [Local development setup](#local-development-setup)
1. [Custom configuration options](#custom-configuration-options)
1. [Scheduled jobs](#scheduled-jobs)
1. [Custom commands](#custom-commands)
1. [Receiving emails locally](#recieving-emails-locally)

## Local development setup

This project uses [Laravel Sail](https://laravel.com/docs/9.x/sail#main-content) for local development.

### Docker

First, you must download [Docker](https://www.docker.com/).

### PHP

In order to install the dependencies required to set up Laravel Sail, you will need PHP installed locally.

* For MacOS users, Homebrew is the recommended way of doing this: `Homebrew install php`
* For Windows users, you may follow [these instructions](https://phptherightway.com/#windows_setup).
* For Linux users, you should install PHP via your distribution's package manager.

### Setup

After you have Docker and PHP installed, navigate to the project directory and run the following:

```bash
composer install
./vendor/bin/sail up
./vendor/bin/sail yarn
```

**Note:** If you have `node` and `yarn` installed locally, you can run `yarn` from your local machine instead of within the Docker container if you'd like.

**Pro tip!** Add the following (or something equivalent) to your shell configuration to use Sail more easily:

```bash
alias sail="bash vendor/bin/sail"
```

### Development

During development, it's recommended to run the following in parallel:

```bash
sail up # starts up Docker container
sail yarn dev # watches for JS/CSS changes
```

## [Custom configuration](https://laravel.com/docs/9.x/structure#the-config-directory)

This project uses the following custom config files:

* [FILE.php](https://github.com/veganhacktivists/REPO/blob/main/config/FILE.php)

## [Scheduled jobs](https://laravel.com/docs/9.x/scheduling#main-content)

This project has the following scheduled jobs:

* [JOB_NAME](https://github.com/veganhacktivists/REPO/blob/main/app/Jobs/JOB_NAME.php): This job sends a weekly email to users letting them know about something.

## [Custom commands](https://laravel.com/docs/9.x/artisan#writing-commands)

This project has the following commands:

-   [COMMAND](https://github.com/veganhacktivists/REPO/blob/main/app/Jobs/COMMAND_NAME.php): This command prints out a list of all users who have this setting set.

## Receiving emails locally

In order to check emails sent locally, visit `http://localhost:8025` to access [MailHog](https://github.com/mailhog/MailHog), which is [provided by Laravel Sail](https://laravel.com/docs/9.x/sail#previewing-emails)


```

# Base Editorconfig Config

Use these as a starting point for [Editorconfig](https://editorconfig.org/) configuration on Vegan Hacktivists projects.

```editorconfig
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[*.php]
indent_size = 4

[*.md]
trim_trailing_whitespace = false

[docker-compose.yml]
indent_size = 4

```

# Base Prettier Config

Use these as a starting point for Prettier configuration on Vegan Hacktivists projects.

## React Projects

```json
{
  "overrides": [
    {
      "files": "*.{js,jsx,ts,tsx}",
      "options": {
        "arrowParens": "always",
        "jsxBracketSameLine": false,
        "parser": "typescript",
        "printWidth": 80,
        "semi": false,
        "singleQuote": true,
        "tabWidth": 2,
        "trailingComma": "all"
      }
    },
    {
      "files": "*.css",
      "options": {
        "parser": "css",
        "printWidth": 80,
        "singleQuote": true,
        "tabWidth": 2
      }
    },
    {
      "files": "*.json",
      "options": {
        "parser": "json",
        "printWidth": 80,
        "tabWidth": 2
      }
    }
  ]
}

```

## Other Projects

Note: You'll want to install the [Laravel Blade plugin for Prettier](https://github.com/shufo/prettier-plugin-blade).

```json
{
  "overrides": [
    {
      "files": "*.js",
      "options": {
        "arrowParens": "always",
        "jsxBracketSameLine": false,
        "parser": "babel",
        "printWidth": 80,
        "semi": false,
        "singleQuote": true,
        "tabWidth": 2,
        "trailingComma": "all"
      }
    },
    {
      "files": "*.css",
      "options": {
        "parser": "css",
        "printWidth": 80,
        "singleQuote": true,
        "tabWidth": 2
      }
    },
    {
      "files": "*.json",
      "options": {
        "parser": "json",
        "printWidth": 80,
        "tabWidth": 2
      }
    },
    {
      "files": "*.blade.php",
      "options": {
        "parser": "blade",
        "sortTailwindcssClasses": true,
        "tabWidth": 2
      }
    }
  ]
}


```

# Base ESLint Config

Use these as a starting point for [ESLint](https://eslint.org/) configuration on Vegan Hacktivists projects.

## `.eslintrc.js`

```js
/** @type import('eslint').Linter.Config */
module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
  },
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    project: './tsconfig.json',
  },
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:@typescript-eslint/recommended',
  ],
  overrides: [],
  plugins: ['react', 'react-hooks'],
  rules: {
    'react/require-default-props': ['off'],
    'react/function-component-definition': [
      'warn',
      { namedComponents: 'arrow-function' },
    ],
    'prefer-arrow-callback': ['warn'],
    'react/prop-types': ['off'],
    'react-hooks/exhaustive-deps': 'warn',
    'react/no-unescaped-entities': 'off',
  },
  ignorePatterns: ['*.js'],
}

```

## `.eslintignore`

```
node_modules
/public
/vendor

```

# Installing Backpack for Laravel

Installing the Backpack admin panel is straightforward, but there are a few extra steps you'll likely want to take.

#### Pro tip!

Add the following to your shell configuration file: `alias sail='bash vendor/bin/sail'`

## Set Up Admin Users

The first thing you'll want to do is to create the concept of user roles in your project. Let's start by creating a migration for this in order to add a `role` field to your `users` table:

```bash
sail artisan make:migration add_role_to_users_table

```

Open the new migration file and add the new field:

```php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
  public function up()
  {
    Schema::table('users', function (Blueprint $table) {
      $table->string('role');
    });
  }

  public function down()
  {
    Schema::table('users', function (Blueprint $table) {
      $table->dropColumn('role');
    });
  }
};

```

#### ⚠️ Notes

- You may be tempted to make `role` an `enum` field. This is [generally not advisable](https://chateau-logic.com/content/why-we-should-not-use-enums-databases), so please make it a normal `string` field instead. Also, do not provide a default value, as this is typically better handled in our application layer.
- A common alternative implementation is to set a `boolean` `is_admin` field. This is fine, but offers less flexibility for potential features down the line.

Next, let's create a *PHP enum* to help keep track of user roles:

```php
<?php
/**
 * app/Enums/UserRole.php
 */

namespace App\Enums;

enum UserRole: string
{
  case User = 'USER';
  case Admin = 'ADMIN';
}

```

Next, let's change the `User` model to support this new field.

```php
<?php

namespace App\Models;

// ... 

class User extends Authenticatable
{
  // ...

  protected $attributes = ['role' => UserRole::User];
  
  protected $fillable = ['name', 'email', 'password', 'role'];

  protected $casts = [
    // ...
    'role' => UserRole::class,
  ];
}

```

The `$attributes` property allows you to specify a default value for fields on a model. Here, we are making users non-admins by default.

The `$casts` property allows us to specify how to cast values from the database to PHP classes. In this case, we're turning plain strings (`USER` and `ADMIN`) into PHP enums.

The `$fillable` property allows us to specify which fields can be ["mass assigned"](https://laravel.com/docs/9.x/eloquent#mass-assignment).

## Download and Install Backpack

Now that you have admin users set up, download Backpack from the Composer. Run the following in your project's root folder:

```bash
# This assumes you have `sail` aliased to `vendor/bin/sail`
sail composer require backpack/crud

```

After that, run the installation command and follow the prompts:

```bash
sail artisan backpack:install

```

- When asked if you'd like to create a new admin user, say `no`.
- When asked if you'd like to install premium functionality, choose `Backpack Pro`. The credentials can be found in Keybase (go to "Files" under the `veganhacktivists.admin` team.

Now, you've officially got Backpack installed! You're almost done.

## Keeping the Repository Clean

You may have noticed that Backpack dumps a huge number of files into `public/packages`. These don't really need to be checked in to the repository, so let's fix that by running the following command:

```bash
cd public && ln -s ../vendor/backpack/crud/src/public/packages packages && cd -

```

This creates a symlink from `public/packages` to the package's own copy of the directory.

Thanks to Joaquín for sharing this tip!

## Configuring and Customizing Backpack

By default, Backpack has a login routes, which requires you to log in to access the admin panel even if you're already logged in as an admin user. Let's change that to make things more convenient by editing `config/backpack/base.php`:

```php
<?php

return [
  // ...
  'setup_auth_routes' => false, // (change from `true`)
  
  'guard' => null, // (change from 'backpack')
];

```

Now, you will only need to log in once. However, we now need to define a custom logout route for Backpack. We do this in `routes/backpack/custom.php`:

```php
<?php

// ...
use Laravel\Fortify\Http\Controllers\AuthenticatedSessionController;

Route::group(
  [/* Leave this alone */],
  function () {
    // ...
    Route::get('logout', [AuthenticatedSessionController::class, 'destroy']);
  }
); // this should be the absolute last line of this file

```

Thanks to Jeremy for sharing this tip!

#### ⚠️ Notes

- This snippet assumes that you have [Laravel Fortify](https://laravel.com/docs/9.x/fortify#main-content) installed. If you are using Laravel Jetsream (which is recommended), this is included.
- Typically, we want session management to handled inside of a `POST` request, but Backpack expects it to be a `GET`, hence why we do it that way in this instance.
- Because this new route was created in `routes/backpack/custom.php`, the URI will automatically be prepended with `/admin/`, so the full path to the logout route will be `/admin/logout`.

Logging out from the admin panel should now work! Now, we need to change one more file.

Right now, all users are considered admins, so we need to fix that. Also, if you try to access `/admin` while being logged out, it will redirect you to `/admin/login`, which no longer exists. In order to change this behavior, open `app/Http/Middleware/CheckIfAdmin.php`:

```php
<?php

// ...

class CheckIfAdmin
{
  private function checkIfUserIsAdmin($user)
  {
    // USE OUR `role` FIELD
    return $user->role === UserRole::Admin;
  }

  private function respondToUnauthorizedRequest($request)
  {
    if ($request->ajax() || $request->wantsJson()) {
      return response(trans('backpack::base.unauthorized'), 401);
    } else {
      // REPLACE THIS
      // return redirect()->guest(backpack_url('login'));
      return redirect()->guest(route('login'));
    }
  }
  
  // ...
}

```

You're officially done setting up Backpack!

## Bonus: Creating An Admin User

Now that Backpack is set up, you'll need a way to access the admin panel. First, sign up for an account using the project's registration form. After that, let's set the user's role using Tinker:

```bash
sail artisan tinker

```

When the prompt is ready for your input, enter the following, making sure to retrieve the correct user:

```php
use App\Enums\UserRole;
$user = User::first();
$user->role = UserRole::Admin;
$user->save();

```

Exit Tinker (Ctrl + D), and you should now be able to visit `/admin` using your admin account.

## Bonus: Displaying Users in Backpack

Now that everything's set up, let's set up Backpack to allow us to perform CRUD operations on our users.

First, let's create a `CrudController` for our users:

```bash
sail artisan backpack:crud user

```

When prompted about validation rules, the default option (`request`) is fine. After the command runs, you will have a new file to configure the new "Users" section in the admin panel: `app/Http/Controllers/Admin/UserCrudController.php`.

#### ⚠️ Note

If the command failed and complained about an undefined array key, then you likely modified the last line in your `routes/backpack/custom.php` file. Make sure that the very last is `}); // this should be the absolute last line of this file`. It's silly, but that's how they add the route to your routes file automatically.

If you visit `/admin/user`, you will see a list of your users. **Whoa**, is that a password hash we see in the table? To remove it (and to add our `role` field), let's open the new controller (`app/Http/Controllers/Admin/UserCrudController.php`):

```php
<?php

namespace App\Http\Controllers\Admin;

// ...
class UserCrudController extends CrudController
{
  // ...
  use App\Enums\UserRole;
  
  public function setup()
  {
      // ...
  }
  protected function setupListOperation()
  {
    // Pro tip: Replace `CRUD::` with `$this->crud->` in order to allow
    //          for better intellisense
    $this->crud->column('name');
    $this->crud->column('email');
    CRUD::column('password'); // remove this line
    $this->crud->column('role')->type('enum');
  }

  protected function setupShowOperation()
  {
    $this->crud->column('name');
    $this->crud->column('email');
    $this->crud
      ->column('role')
      ->type('enum');
    $this->crud->column('created_at')->type('datetime');
    $this->crud->column('updated_at')->type('datetime');
  }

  protected function setupCreateOperation()
  {
    $this->crud->setValidation(UserRequest::class);

    $this->crud->field('name');
    $this->crud->field('email');
    $this->crud->field('password');

    $this->crud
      ->field('role')
      ->type('enum');
  }
  // ...
}

```

## Bonus: Fixing Update/Create Functionality

By default, Backpack requires that you set a pre-hashed password in the "Password" field in order to create or update a user. This is not desirable behavior, so let's fix that.

First, let's open `app/Http/Requests/UserRequests.php` and make passwords optional when updating a user:

```php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Laravel\Fortify\Rules\Password;

class UserRequest extends FormRequest
{
  // ...

  public function rules()
  {
    return [
      'password' => [
        $this->method() === 'POST' ? 'required' : 'optional',
        'string',
        new Password(),
      ],
    ];
  }
  // ...
}

```

Next, we will update `app/Http/Controllers/Admin/UserCrudController.php` to [hash passwords before storing them](https://backpackforlaravel.com/docs/5.x/crud-fields#password-1), and to omit them from the update if they haven't been provided:

```php
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Requests\UserRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Illuminate\Support\Facades\Hash;

class UserCrudController extends CrudController
{
  // ...
  use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation {
    store as traitStore;
  }

  use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation {
    update as traitUpdate;
  }
  
  // ...

  public function store()
  {
    $this->crud->hasAccessOrFail('create');
    $this->crud->setRequest($this->crud->validateRequest());

    $request = $this->crud->getRequest();

    // Encrypt password if specified.
    if ($request->input('password')) {
      $request->request->set(
        'password',
        Hash::make($request->input('password'))
      );
    } else {
      $request->request->remove('password');
    }

    $this->crud->setRequest($request);
    $this->crud->unsetValidation(); // Validation has already been run

    return $this->traitStore();
  }

  public function update()
  {
    $this->crud->hasAccessOrFail('update');
    $this->crud->setRequest($this->crud->validateRequest());

    $request = $this->crud->getRequest();

    // Encrypt password if specified.
    if ($request->input('password')) {
      $request->request->set(
        'password',
        Hash::make($request->input('password'))
      );
    } else {
      $request->request->remove('password');
    }

    $this->crud->setRequest($request);
    $this->crud->unsetValidation(); // Validation has already been run

    return $this->traitUpdate();
  }
}

```

#### ⚠️ Note

In order for a CRUD form to work, all fields in the form must be defined in the `$fillable` property on your model.

# Setting Up Cron Jobs on Laravel Forge

In the Laravel world, we are able to set up recurring tasks/jobs in a more flexible way than using tradition cron jobs. This is because we are able to control the schedule in our code, and we only need to create a single cron job per project.

## Creating a Task

There are multiple ways to do this. For the full details, refer to the Laravel documentation for [task scheduling](https://laravel.com/docs/9.x/scheduling#main-content). However, here's a quickstart:

First, [create a job](https://laravel.com/docs/9.x/queues#creating-jobs) using the `artisan` command:

```bash
sail artisan make:job SendWeeklyEmail

```

#### Pro tip!

Add the following to your shell configuration file if you haven't yet: `alias sail='bash vendor/bin/sail'`

After the job is created, implement the desired functionality in the `handle()` function. Consult the official documentation for an explanation of the generated file.

Next, you'll want to open `app/Console/Kernel.php` and modify the task schedule. Something like this:

```php
<?php

namespace App\Console;

use App\Jobs\SendWeeklyEmail;

class Kernel extends ConsoleKernel
{
    // ...
  
    protected function schedule(Schedule $schedule)
    {
        $schedule
            ->job(new SendWeeklyEmail())
            ->weekly()
            ->wednesdays()
            ->at('0:0')
            ->withoutOverlapping();
    }
}

```

[The documentation](https://laravel.com/docs/9.x/scheduling#schedule-frequency-options) lists all of the scheduling options at your disposal.

### Running the Scheduler on Forge

Now that the code is all set up, head to the "Scheduler" page on [Laravel Forge](https://forge.laravel.com).

[![forge-cron-jobs-scheduler-link.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-cron-jobs-scheduler-link.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-cron-jobs-scheduler-link.png)

#### ⚠️ Note

Only team leaders have access to Laravel Forge [credentials](https://docs.veganhacktivists.org/books/technology-at-vegan-hacktivists/page/credential-sharing). If you are a team leader without access, ask one of the Directors to add you to the `veganhacktivists.admin` team on Keybase. **If you are not a team leader, have them set this up for the project.**

On the Scheduler page, expand the "New Scheduled Job" section in order to set up the scheduler.

[![forge-new-scheduled-job.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/laravel-forge-new-scheduled-job.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/laravel-forge-new-scheduled-job.png)

The form is prefilled with everything you need, but you'll need to change a couple things.

### For Isolated Projects

If the project was started in 2021 or later and was set up properly, it should be isolated. In that case, make the following changes:

1. Update the `artisan` path in the "Command" field to be `/home/USERNAME/PROJECT_NAME.org/artisan`.
2. Update the "User" field to the appropriate user for the project (same as `USERNAME` above).

More likely than not, the username is the project's domain without the dot (`.`), and the project directory is the domain. If you are unsure, visit the [list of sites](https://forge.laravel.com/servers/278609/sites) on Forge and check there:

[![forge-site-list-directory-username.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-site-list-directory-username.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-site-list-directory-username.png)

### For Non-Isolated Projects

If the project was started before 2021, it may not be isolated. If that's the case, update the artisan path in the "Command" field to be `/home/forge/PROJECT_NAME.org/artisan`. The "User" field can stay `forge`.

### For Projects With [Zero-Downtime Deployments](/books/recipes/page/setting-up-zero-downtime-deployment)

If the project is set up on Laravel Envoyer, then you'll need to make further changes to the "Command" field by adding the `/current` directory. It should follow this format: `/home/USERNAME/PROJECT_NAME.org/current/artisan`.

## That's It!

Your project's scheduler will now run every minute. From your project's code, you can continue to add more tasks to the scheduler and change the timing of existing tasks. You won't need to touch the cron job for this project again!

To make sure things are working, it's recommended to [implement logging](https://laravel.com/docs/9.x/logging#main-content) which can be viewed directly from Forge:

[![forge-site-logs.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-site-logs.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-site-logs.png)

If you would like to see the output of the actual cron job which runs every minute, you can also do this in Forge:

[![forge-scheduler-show-output.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-scheduler-show-output.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-scheduler-show-output.png)

# Setting Up Job Queues on Laravel Forge

There are certain times when we want to run code *outside* of the request lifecycle. For example, if a user signs up for our website and we want to send them an email, we don't want to wait until the email is sent before letting the user proceed. This is where [job queues](https://laravel.com/docs/9.x/queues) come into play. Laravel and Laravel Forge make setting up a queue extremely easy.

### ⚠️ Note

You will need access to Forge [credentials](/books/technology-at-vegan-hacktivists/page/credential-sharing) in order to set up a queue worker. If you are not a team leader, then have them set this up.

To start a new queue worker, head to your project's page on [Laravel Forge](https://forge.laravel.com/servers/278609/sites) and open the "Queue" tab:

[![forge-new-queue-worker.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-new-queue-worker.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-new-queue-worker.png)

The default values should be fine. Only change them if you really know what you're doing! There is one exception, however:

**If your project has zero-time deployments set up via [Envoyer](https://docs.veganhacktivists.org/books/recipes/page/setting-up-zero-downtime-deployment), you must manually set the working directory!** All you need to do in this case is add `/current` to the default directory. For example, if your project is located at `/home/exampleorg/example.org`, then your working directory should be `/home/exampleorg/example.org/current`.

# Recommended VS Code Setup

Below is a list of recommended plugins to use while developing Vegan Hacktivists projects.

## Crucial

- [EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) - This adds [EditorConfig](https://editorconfig.org/) support to VS Code to set up project-specific rules for indentation and other things.
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Integrates [ESLint](https://eslint.org/) functionality to VS Code for real-time warnings/errors about your code.
- [Laravel Pint](https://marketplace.visualstudio.com/items?itemName=open-southeners.laravel-pint) - Integrates [Laravel Pint](https://laravel.com/docs/9.x/pint) into VS Code to format your PHP code appropriately.
- [laravel-blade](https://marketplace.visualstudio.com/items?itemName=cjhowe7.laravel-blade) - Adds syntax highlighting for [Blade template](https://laravel.com/docs/9.x/blade#main-content) files.
- [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Automatically formats code according to the project's [Prettier](https://prettier.io/) configuration file.

## Highly Recommended

- [DotENV](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv) - Syntax highlighting/autocomplete for `.env` files.
- [Laravel Extra Intellisense](https://marketplace.visualstudio.com/items?itemName=amiralizadeh9480.laravel-extra-intellisense) - Adds Laravel-specific Intellisense functionality for a much better autocomplete experience (routes, config options, environment variables, etc.).
- [PHP Intelephense](https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client) - Similar to the above, but for PHP code in general.

## Nice to Have

- [Laravel Blade Spacer](https://marketplace.visualstudio.com/items?itemName=austenc.laravel-blade-spacer) - Adds automatic spacing for [Blade template](https://laravel.com/docs/9.x/blade#main-content) markers (e.g. `{{ }}`).

# Setting Up Mailgun

For the vast majority of projects, we'll need to make use of email in some way. At the very least, projects where users have accounts will need the ability to reset their passwords via their email inbox.

Vegan Hacktivists uses [Mailgun](https://mailgun.com) to send emails for all of our projects, so here's how to set that up.

### ⚠️ Notes

- This guide should likely be followed by the project's team leader.
- You will need access to Laravel Forge, Mailgun, and Cloudflare. If you don't have access to them, reach out to David to get Forge [credentials](/books/technology-at-vegan-hacktivists/page/credential-sharing) to get added as a collaborator to the other accounts.
- The project should already be [set up on Cloudflare](/books/recipes/page/cloudflare-domain-setup).

## Add the Domain

The first step will be adding the domain to Mailgun. Head to Mailgun's website and log in. To do that, click on "Sending" in the sidebar, then "Domains," and then "Add New Domain."

[![mailgun-domains.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/mailgun-domains.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/mailgun-domains.png)

Like Mailgun says, it's recommended to add a subdomain, rather than the root domain. The convention we use is prepending the project's domain with `mail.`, so for `veganlinguists.org`, we added `mail.veganlinguists.org` to Mailgun.

As for the region, it doesn't really matter.

## Setting DNS Records

After adding the domain, you will be shown a list of DNS records we must add in our DNS settings. For this, head over to [Cloudflare](https://dash.cloudflare.com/) and go into the Vegan Hacktivist account:

[![cloudflare-vh-account.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/cloudflare-vh-account.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/cloudflare-vh-account.png)

Find your project's domain name in the list of domains or use the search bar to help. Once found, click on the domain, and then click "DNS" on the sidebar:

[![cloudflare-dns-records.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/cloudflare-dns-records.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/cloudflare-dns-records.png)

Now, it's time to add the DNS records that Mailgun provides, of which there should be five. Go down the list on Mailgun and add each one by clicking the "Add record" button and filling out the form with the values that Mailgun provides. Below are a couple of examples:

[![mailgun-mx-records.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/mailgun-mx-records.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/mailgun-mx-records.png)

[![cloudflare-new-dns-record-1.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/cloudflare-new-dns-record-1.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/cloudflare-new-dns-record-1.png)

[![cloudflare-new-dns-record-2.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/cloudflare-new-dns-record-2.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/cloudflare-new-dns-record-2.png)

Once all of the DNS records are added, go back to Mailgun and click on one of the "Verify DNS settings" buttons:

[![mailgun-verify-dns.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/mailgun-verify-dns.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/mailgun-verify-dns.png)

### ⚠️ Note

For the final DNS record (the `CNAME` one), make sure to disable proxying after it's been added:

[![cloudflare-disable-cname-proxy.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/cloudflare-disable-cname-proxy.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/cloudflare-disable-cname-proxy.png)

More likely than not, at least one of the records will fail to be verified right away. If this happens, just wait ten minutes or so and try again. If an hour goes by and things are still failing, then you may need to double-check to make sure everything was entered correctly.

Once all of the DNS settings are verified, the page will refresh and you'll be redirected to another page.

## Updating Environment Variables

The next step is to get our project to send email using Mailgun. Mailgun's UI is very confusing for this, so let's walk through it.

First, click on "Overview" on the sidebar and then open the "SMTP Credentials" tab. **Make sure that the domain in the dropdown in the top left is the correct one for your project:**

[![mailgun-smtp-creds.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/mailgun-smtp-creds.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/mailgun-smtp-creds.png)

At this point, you have two options (either is fine):

1. Reset the password for the default SMTP user.
2. Create a new SMTP user.

Copy the password for the SMTP user and save it for the next step. Keep this tab open for the other things we'll need as well!

Next, we need to head over to [Forge](https://forge.laravel.com/servers/278609/sites) and navigate to your project's environment variables:

[![forge-env-mail.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-env-mail.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-env-mail.png)

By default, Laravel has environment variables to make setting up email very simple. All we need to do is take the credentials from Mailgun and add them to the project's environment variables.

### ⚠️ Note

While Mailgun provides you with three different port options, they actually [recommend](https://www.mailgun.com/blog/email/which-smtp-port-understanding-ports-25-465-587/#subchapter-5) using port 587, so please choose that.

After saving the environment variable changes, you should now officially be able to [send mail](https://laravel.com/docs/9.x/mail#sending-mail) from your project!

# GitHub Repository Setup



# Cloudflare Domain Setup

Below is the process for setting up domains with Cloudflare.

## Why do we use Cloudflare?

Cloudflare is essentially a web performance and security company that provides a range of services to improve the performance and security of websites. Some of the benefits of using Cloudflare for VH includes:

- **Improved website performance:** Cloudflare's content delivery network (CDN) helps to reduce the load on our servers, and speeds up the delivery of our content to our visitors.
- **Enhanced security:** Cloudflare offers a range of security features to protect our projects from various threats such as DDoS attacks, malware, and spam.
- **Easy and cost effective:** Setting up Cloudflare is relatively easy and does not require any technical expertise. Cloudflare's basic plan is free and provides many of the features that are essential for most websites. There are also paid plans, but we don't have a need for it.

Overall, using Cloudflare helps improve the performance and security of our projects.

## How to set up an existing domain

To set up a domain with Cloudflare from another registrar, **follow these steps:**

1. Go to [Cloudflare's website](https://www.cloudflare.com/) and login with your account. Note that you'll need to have been given permission to edit VH's websites on Cloudflare by one of the core team members with access.
2. After logging in, click on the "Add a Site" button and enter your new domain name. Cloudflare will scan our DNS records and show you a list of all the DNS records for this domain.

**Note:** This is the step where you'll want to make sure to add DNS records that point to our Digital Ocean droplet.

**Add the following two records:**

- TYPE: "A", NAME: "@", CONTENT: "134.209.65.245"
- TYPE: "CNAME" NAME: "www", CONTENT:"yourdomainname.org"

3. Select the DNS records that you want to keep and click on the "Continue" button.
4. Review the DNS records and make sure they are correct. If everything looks good, click on the "Confirm and Continue" button.
5. Cloudflare will now provide you with two DNS servers that you need to use to point your domain to Cloudflare.
6. Go to our domain registrar's website (e.g. Namecheap, which we normally use) and log in to our account.
7. Find the DNS settings for your domain and replace the existing DNS servers with the ones provided by Cloudflare. This process may vary depending on your domain registrar.
8. Once you have updated your DNS servers, return to the Cloudflare dashboard and click on the "Recheck Nameservers" button. Cloudflare will now check to see if your domain is properly pointed to their servers.
9. If the nameservers check is successful, click on the "Continue" button to proceed with the setup process. Choose the free plan, which is a bit hidden below the other plans.
10. Cloudflare will now start the process of setting up our domain on their platform. This process may take some time.

**That's it!** You have now successfully set up our domain with Cloudflare.

## How to set up a brand new domain

If you don't have a domain yet, you can buy it on Cloudflare directly, in which case none of the steps above are nessesary. This is usually always preffered, so if you can, buy the domain on Cloudflare.

1. Go to [Cloudflare's website](https://www.cloudflare.com/) and login with your account. Note that you'll need to have been given permission to edit VH's websites on Cloudflare by one of the core team members with access.
2. After logging in, click on the "Domain Registration" button on the left sidebar, below "Websites".
3. Then click "Register Domains", type the domain you'd like to buy, search, and purchase.
4. Once purchased, you'll need to point the domain to our Digital Ocean Droplett.
5. Go back to the domain, select "DNS", and add 2 records:

- TYPE: "A", NAME: "@", CONTENT: "134.209.65.245"
- TYPE: "CNAME" NAME: "www", CONTENT:"yourdomainname.org"

Hit save. **You're done!**

Cloudflare will now start the process of setting up our domain on their platform. This process may take some time.

### Important for SquareSpace

If you're adding a domain that will be pointed to SquareSpace, make sure to turn off th Proxied status. This will be a yellow cloud icon that shows up next to each record in the DNS settings for the domain. If you click on the cloud icon, it should turn gray, and that should allow SquareSpace to successfully connect.

**Still having issues** with connecting to SquareSpace? Contact James, our Director of Operations.

# Hosting a Project on Forge

[Laravel Forge](https://forge.laravel.com) makes hosting a project super easy, but there are some things worth going over to make sure everything is done correctly.

## Prerequisites

- You will need [access](/books/technology-at-vegan-hacktivists/page/credential-sharing) to Laravel Forge.
- The project must have a domain set up on [Cloudflare](/books/recipes/page/cloudflare-domain-setup) pointing to `134.209.65.245`.
- The project will require a repository hosted on GitHub.

## Create a New Site

The first thing you'll need to do is create a new site. Expand the "New Site" form on the page for the Vegan Hacktivists server:

[![forge-new-site.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-new-site.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-new-site.png)

Fill in the form using the project details.

- The "Root Domain" will of course be the domain name associated with the project.
- **The "Project Type" will likely be "General PHP / Laravel,"** but if it's a static website, choose "Static HTML." It will never be any of the Symfony options, and "Laravel Octane" should only be chosen if you *really* know what you're doing.
- **For non-static websites, make sure to check the "Website Isolation" option.** This will make sure that the project is running its own [PHP-FPM](https://www.php.net/manual/en/install.fpm.php) instance, which will help prevent problems from one project affecting other projects.
- In the likely event that your project requires a database, now is a good time to do that. Typically, we name the database after the project name, with no underscores and only lowercase characters (e.g. "Vegan Linguists" becomes "veganlinguists").

## Connect to the GitHub Repository

After creating the project, you should be redirected to the project's page where you can connect it to the GitHub Repository:

[![forge-connect-to-github.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-connect-to-github.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-connect-to-github.png)

[![forge-connect-to-github-2.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-connect-to-github-2.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-connect-to-github-2.png)

Make sure to fill in the "Repository" and "Branch" fields.

If this is a PHP project, make sure to keep "Install Composer Dependencies" checked. If it's a static website that doesn't require PHP packages, you can uncheck it.

### ⚠️ Note

Forge confusingly shows `main` in the "Branch" field, but this is simply placeholder text, and not a default value. You will actually need to choose an option from the dropdown or type in the name of the branch manually.

Once you are done, click the "Install Repository" button.

## Setting Up Deployment

After the repository is installed, we need to make a quick change to the deploy script. By default, Node dependencies aren't installed and assets aren't built, so we need to make sure all of that happens.

After the line in the deploy script, add the following (or your project's equivalent if production assets are built differently):

```bash
yarn && yarn build

```

Also, you will likely want to click the "Enable Quick Deploy" button so that deployment happens as soon as new changes are pushed to the `main` branch.

[![forge-setting-up-deployment.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-setting-up-deployment.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-setting-up-deployment.png)

## Create a Database User

The next step is to create a user that can access the project's database. Head to the server's [databases section](https://forge.laravel.com/servers/278609/databases) and search for the "add database user" form:

[![forge-add-db-user.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-add-db-user.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-add-db-user.png)

1. For the "Name" field, we typically use the name of the database followed by `_user`.
2. Click the ⚙️ gear button next to the "Password" field to generate a password for this user.
3. **Select *only* the database associated with the project.**
4. **Copy the password to your clipboard for the next step.**
5. Click the "Create" button.

## Update the `.env` File

Forge makes updating a project's environment variables very easy. Navigate to the "Environment" section of your project's page and update the `DB_Database`, `DB_USERNAME`, and `DB_PASSWORD` entries:

[![forge-project-environment.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-project-environment.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-project-environment.png)

You can, of course, modify other variables, but the defaults should be good for most projects unless you know what you're doing! The main exception would be the `MAIL_` variables, which [we cover elsewhere](/books/recipes/page/setting-up-mailgun).

## Set Up the Storage Directory

Laravel handles uploaded files using a [symlinked folder](https://laravel.com/docs/9.x/filesystem#the-public-disk), which is something you must set up yourself. Luckily, there is an `artisan` command to do this, which we can run directly from Forge.

Head to the "Commands" section on your project's page and choose the `php artisan storage:link` command from the dropdown menu, then click "Run."

[![veganproject_org___vegan-hacktivists___Laravel_Forge.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/veganproject-org-vegan-hacktivists-laravel-forge.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/veganproject-org-vegan-hacktivists-laravel-forge.png)

## TLS

The last step is setting up TLS, often \[incorrectly\] referred to as SSL. Navigate to the "SSL" section, click "Let's Encrypt," and then "Obtain Certificate." There should be no reason to make modifications to the default values.

[![forge-ssl-setup.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-ssl-setup.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-ssl-setup.png)

### ⚠️ Note

If the domain has not been [propagated](https://www.whatsmydns.net/), the certificate creation may fail. In this case, try again immediately, and if it fails again, try waiting an hour or so. If it continues to fail, double check to make sure that everything is set up correctly on Cloudflare.

## That's It!

You now have a project hosted on Laravel Forge!

# Setting Up Zero-Downtime Deployment

When deploying a project, it can lead to temporary downtime for the production application. In order to avoid this, we use [Laravel Envoyer](https://envoyer.io/) to set up zero-downtime deployments.

## Which Projects Are Elligible?

Before explaining how to set things up, something worth noting is that we shouldn't be setting this up for every single project. The amount of apps that we can use Envoyer for is limited based on how much we pay, so it should only be used for our most important projects.

**Do not** set up Envoyer for the following types of sites:

- Small projects, especially those with little traffic
- Static websites and front-end only applications (i.e. no PHP)
- Staging environments

**Also**, the project should be [set up on Laravel Forge](/books/recipes/page/hosting-a-project-on-forge) before being set up on Envoyer.

## Create the Project

With that disclaimer out of the way, let's do this thing!

First, you'll need to be logged into Laravel Envoyer with the admin account. On the dashboard page, click "Add Project" and fill in the details of the project's GitHub repository:

[![envoyer-new-project.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/envoyer-new-project.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/envoyer-new-project.png)

### ⚠️ Note

Only team leaders have access to the Laravel Envoyer admin account [credentials](/books/technology-at-vegan-hacktivists/page/credential-sharing). If you are a team leader without access, ask one of the Directors to add you to the `veganhacktivists.admin` team on Keybase. If you are not a team leader, have them set this up for the project.

Next, we'll need to import the site from Forge. Head to your new project's page, open the "Servers" tab, and then click "Import Forge Server":

[![envoyer-import-forge-server.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/envoyer-import-forge-server.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/envoyer-import-forge-server.png)

Select the `vegan-hacktivists` server, select the project from the list of sites, and then click "Import Server."

Once this is done, click the refresh ? icon under "Connection Status" in Envoyer:

[![envoyer-connection-status.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/envoyer-connection-status.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/envoyer-connection-status.png)

### ⚠️ Note

You may see a warning that PHP-FPM was unable to be restarted:

[![envoyer-error-php-fpm.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/envoyer-error-php-fpm.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/envoyer-error-php-fpm.png)

If you run into this, it's *likely* because Envoyer set up the project with the wrong PHP version. Check the site on Forge to see what version of PHP the project is using. Then, click on the pencil ✏️ icon in Envoyer to set the correct PHP version for the project. After that, click the refresh ? button again and all should look good!

## Copying From Forge

While we've imported the site from Forge, there are still some things we'll need to do manually in order to complete the Envoyer setup.

### Disable Quick Deploy

The first thing we'll need to do is disable "Quick Deploy" if it's enabled. Head to your project's page on Forge and make sure it's disabled:

[![forge-disable-quick-deploy.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-disable-quick-deploy.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-disable-quick-deploy.png)

We're disabling this because we'll no longer be deploying using Forge. To get the equivalent functionality for the new deployments, head to your project settings on Envoyer:

[![envoyer-settings.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/envoyer-settings.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/envoyer-settings.png)

Then, head to the "Source Control" tab and check "Deploy When Code Is Pushed" and save the project settings:

[![envoyer-push-to-deploy.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/envoyer-push-to-deploy.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/envoyer-push-to-deploy.png)

### Setting Up Deployment Hooks

Now we have to replicate whatever is in our deploy script! First, take a look at what's currently there on Forge:

[![forge-deploy-script.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-deploy-script.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-deploy-script.png)

Keep that tab open and head over to the "Deployment Hooks" tab on your Envoyer project page:

[![envoyer-deployment-hooks.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/envoyer-deployment-hooks.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/envoyer-deployment-hooks.png)

If you are just setting up the project, you will have four immutable hooks (the ones with a gray background). These are managed by Envoyer, but they are likely not enough to cover all of the deployment process, so we'll have to add our own.

#### Migrating the Deploy Script

In order to start adding hooks, click the "Add Hook" button. More-or-less, you'll want to consult your deploy script on Forge.

**Do not write hooks for the following:**

- Pulling the Git repository
- Installing Composer dependencies
- Restarting PHP-FPM

**Also, make sure that the "Run As" field is the username associated with the project.** This can be checked on the [sites page on Forge](https://forge.laravel.com/servers/278609/sites):

[![forge-site-list-directory-username.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-site-list-directory-username.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-site-list-directory-username.png)

Below are some examples which should suffice most projects, but of course, refer to the deploy script to be sure. Refer to the Envoyer screenshot above to see the proper order for these hooks.

Note that `{{release}}` is a template variable for deployment hooks which refers to the directory of the latest release.

##### Build front-end assets

```bash
cd {{release}}

yarn && yarn prod

```

##### Optimize

```bash
cd {{release}}

php artisan optimize

```

##### Run Database Migrations

```bash
cd {{release}}

php artisan migrate --force

```

##### Restart Queue

This is only necessary if you've [set up a queue](/books/recipes/page/setting-up-job-workers-on-laravel-forge) for asynchronous jobs.

```bash
cd {{release}}

php artisan queue:restart

```

#### Linking Storage

You may recall needing to run `php artisan storage:link` when setting up the project on Forge. Since Envoyer uses a new directory for each deploy, we essentially need to run this on every deploy. Luckily, Envoyer has this functionality built-in. Click on the "Manage Linked Folders" button and fill in the the form.

If you have *not* modified the default filesystem storage config, then fill in the following:

- **Create Link At:** `public/storage`
- **To Folder:** `storage/app/public`

This corresponds with the filesystem config in your project's repository (`config/filesystem.php`):

```php
<?php
    // ...
    'links' => [
        //   public/storage            storage/app/public
        public_path('storage') => storage_path('app/public'),
    ],
    // ...

```

If you're unsure, consult the config file to see which directories you need to link!

### Updating the Scheduler

If your project makes use of [scheduled tasks](/books/recipes/page/setting-up-cron-jobs-on-laravel-forge), then there is one more thing to do before completing the deployment setup, which is updating the directory where the scheduler runs.

Head over to the "Scheduler" section for the server on Forge and copy the scheduler command for your project:

[![forge-copy-scheduled-job.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-copy-scheduled-job.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-copy-scheduled-job.png)

After copying the command, create a new scheduled job and paste that command into the "Command" field. Make sure that the "User" field matches the user running the existing command as well.

**Important:** After copying everything over, update the "Command" field so that `artisan` is run inside the `current` directory. For example, if your command was previously:

```bash
php8.0 /home/veganorg/vegan.org/artisan schedule:run

```

Change it to:

```bash
php8.0 /home/veganorg/vegan.org/current/artisan schedule:run

```

Create the new job and then delete the old one:

[![forge-delete-old-scheduled-job.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-delete-old-scheduled-job.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-delete-old-scheduled-job.png)

### Updating the Queue Worker(s)

If your project has a [job queue](/books/recipes/page/setting-up-job-queues-on-laravel-forge) set up, you'll need to make sure that it's running `artisan` in the `current` directory.

First, follow [the instructions](/books/recipes/page/setting-up-job-queues-on-laravel-forge) on how to set up a queue worker. Aside from the working directory, use the same settings as the current worker (likely default). After that, delete the old queue worker:

[![forge-delete-queue-worker.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-delete-queue-worker.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-delete-queue-worker.png)

## Wrapping Up

There's only one more thing we need to do in order to complete the setup, which is updating the directory serving our project.

To make sure the transition is as smooth as possible, deploy the application via Forge first:

[![envoyer-deploy.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/envoyer-deploy.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/envoyer-deploy.png)

Once it's done, open the "Meta" tab for your project on Laravel Forge and prepend the "Web Directory" with `/current`:

[![forge-update-web-directory.png](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/scaled-1680-/forge-update-web-directory.png)](https://docs.veganhacktivists.org/uploads/images/gallery/2022-12/forge-update-web-directory.png)

Wait a few seconds and then visit the site. If it loads, then you should be good to go! If you get an error, then revert the "Web Directory" change and debug using the logs on Laravel Forge.

# Open sourcing our projects on GitHub

Our mission is to use technology to help animals and promote animal rights. Open sourcing our projects is one way we strive to achieve this goal. We welcome contributions from others who share our passion and want to help animals through technology.

## Contributing Guidelines

Contributing guidelines are a set of rules and instructions that explain how to contribute to a project. They outline the process for submitting issues, creating pull requests, and getting in touch with the maintainers of the project. By following these guidelines, we aim to ensure that all contributions are made in a consistent and manageable way.

1. Create a CONTRIBUTING file that outlines the process for contributing to the project.
2. Mention the contribution guidelines in the README file and include a link to the CONTRIBUTING file.
3. Explain how to file an issue, create a pull request, and get in touch with the maintainers of the project.

## License

1. Choose the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html) (GPLv3), which promotes the use of open source software for non-profit purposes.
2. Include the license file in the root directory of the repository.
3. Ensure that all code contributions are made under the same license.

## Readme File

1. Create a comprehensive README file that explains the purpose and goals of the project, how to install and use it, and how to contribute to its development.
2. Provide clear instructions for setting up the development environment and any dependencies required.
3. Mention the contribution guidelines and the link to the CONTRIBUTING file.

## Documentation

1. Ensure that the code is well-documented and that all functions, classes, and methods have descriptive docstrings.
2. Consider creating additional documentation, such as API documentation or a user manual, to help others understand and use the project.

## Tests (Optional)

1. Write automated tests to ensure the reliability and maintainability of the code.
2. Make sure that the tests pass before open sourcing the project.

## Security

1. Keep the dependencies of your project up-to-date to prevent known vulnerabilities from being exploited.
2. Consider using tools such as [Snyk](https://snyk.io/) or [OWASP Dependency-Check](https://owasp.org/projects/dependency-check/) to scan your dependencies for vulnerabilities.
3. Encourage responsible disclosure of security vulnerabilities through a [security.txt](https://securitytxt.org/) file and/or a [bug bounty program](https://bugcrowd.com/).

We believe that by open sourcing our projects and encouraging others to contribute, we can help more animals and make a greater impact. We welcome competition in the animal rights technology space, as our ultimate goal is to save as many lives as possible.

# Process GDPR data deletion request

### Verification Template

Hi there,

Thanks for getting in touch about your data deletion request. To move forward, we just need a quick confirmation to make sure you own this email address.

Could you please reply with something like:

"I confirm that I own this email address and requested the deletion of my personal data from Vegan Hacktivists."

This will help us document your request and get things processed as quickly as possible.

Appreciate your cooperation, and we’ll handle the rest once we hear back!

### Current Databases with User Data

The connection has to be setup via ssh tunnel. The IP next to the project name is the ip used for the ssh tunnel, the port is for the database

- 5 minutest 5 vegans. 65.21.184.160:5992
- Activisthub 65.21.184.160:5993
- Fast Forum 37.27.25.27:5989
- Fast List 37.27.25.27:3908
- Granti: 37.27.25.27:5214
- TodayForAnimals 65.21.184.160:5990
- Vegan Activism 65.21.184.160:3909
- VBCC 65.21.184.160:5995
- Vegan Bootcamp 65.21.184.160:6732
- Vegan Bootcamp Forum 65.21.184.160:5996
- Vegan Linguists 65.21.184.160:5997
- VH.org 65.21.184.160:5989