# Raven

Build common blocks and files insanely faster!

## How does it work?

### General working principle

We use pre-built (.txt) templates and components to be copied from our library, get some modifications based raven config file contents & your answers to the CLI prompt questions, and finally pasted as (.ts) files into your project.

### Cloning and Injection

We have 2 processes to complete the previously mentioned action, cloning and injection. The tool clones the (.txt) files and replaces the placeholders with the given processed answers before the're placed in the given location. Then it injects some blocks of code in different files so you don't need to modify **ANYTHING**.

## Before starting

### Comments

You'll notice some comments in the generated files. We use those to locate the place in the code where the new blocks should be injected. Therefore, you can **only remove** them after you finish using the tool to build the blocks.

### Placeholders

You might also notice some placeholder variables or values written in an uppercase format (e.g: `FIELD_NAME`). TypeScript will notify you about them (since they're not defined). You can change those whenever you want since their purpose is just to let you know about the options without causing runtime errors.

### Versions

Make sure to have the exact versions for your installed libraries corresponding to each framework to avoid unexpected errors due to the constant updates on the libraries.

**Nest.js**

| Library                  | Preferred used version |
| ------------------------ | :--------------------: |
| @nestjs-modules/mailer   |         2.0.2          |
| @nestjs/common           |         11.0.1         |
| @nestjs/config           |         4.0.0          |
| @nestjs/core             |         11.0.1         |
| @nestjs/jwt              |         11.0.0         |
| @nestjs/platform-express |         11.0.9         |
| @nestjs/serve-static     |         5.0.2          |
| @nestjs/swagger          |         11.0.3         |
| @nestjs/schedule         |         6.0.0          |
| @nestjs/typeorm          |         11.0.0         |

## Getting started

### Installation

- Install **nest-cli** globally:  
     `npm install -g @nestjs/cli`

- Install **raven** globally:  
     `npm install -g @kaiserleap/raven`

- Create a new project:  
     `nest new project-name`  
     `cd project-name`

### Set up your credentials (this is currently disabled due to technical concerns)

- You need to provide a valid credentials for the tool to work, you can use these temporary credentials during the development phase of the project to use the app for the moment. Run the following command:

> Note that in order for Raven to work, you need to provide credentials to the cli (use any dummy credentials for now since the tool is in its MVP phase)

```bash
raven login --email example@email.com --pass xxxxxx
```

### Commands API

#### The `init` command

Install the recommended dependencies in your project if they're not yet installed. These are different from the ones installed using `nest new` command by default.

It also initialize the raven config file `raven.config.json` at the root of your project which will have the entire structure of your backend.

> Usage: `raven init`

##### The list of dependencies

```json
"@nestjs/config"
"@nestjs/typeorm"
"@nestjs/platform-express"
"@nestjs/serve-static"
"@nestjs/swagger"
"class-validator"
"class-transformer"
"express-session"
"typeorm"
"mysql2 "
"pg"
"uuid"
"bcrypt"
"fs"
```

##### The list of dev-dependencies

```json
"@types/multer"
"@types/bcrypt"
"prettier"
```

<!-- ## The `dockerize` command

Dockerize the application with the necessary modifications to the config files.

> Usage: `raven dockerize`

### Created Images

-   **postgres-db**: an image for initializing a PostgreSQL DB in the container.

-   **nest-app**: the main image that runs the application. -->

#### The `build` command

This is the main and most important command in the system, it removes the default out directory `./src` and rebuild it from scratch. It uses the specifications provided in the `raven.config.json` to do the following:

- Build your tables, columns, relations, validators, and enums.
- Utilize your env section to validate your `.env` file.

### Start using the project

- Install the recommended dependencies and get the initial dev-kit:  
     `raven init`

- Duplicate empty .env.example into .env  
     `cp .env.example .env`

- Build the initial example:  
     `raven build`

- In your code editor, replace all './src/' with 'src/'. **We are working to fix this error automatically, but for now you need to fix manually as stated**

- Duplicate populated .env.example into .env  
     `cp .env.example .env`

- Rename main branch into prod **this is essential for github workflows to function**
     `git branch -m prod`

- Run the project:  
     `npm run dev`

> **Now you're ready to go!**

> **Database is already seeded with an admin user with credentials found in swagger login api example**

## The Raven Config File

Raven works by reading a file at the root of your project named `raven.config.json`, and turn its instructions to actual code (files and directories). This file contains the structure of your entire project where your can control the resultant code using the json contents.

The config file consists of the following sections:

### The `project` section

This sub-json contains basic info about your project:

#### 'Project' Options

| Key       | Description                              | Type                                          |
| --------- | ---------------------------------------- | --------------------------------------------- |
| framework | The currently used framework             | Supported values: `nest.js`                   |
| name      | The name of your project                 | String value                                  |
| version   | The current version of your project      | String value follows versions format: `1.0.0` |
| outDir    | The destination directory of the project | String value                                  |
| debugger  | Activate/Deactivate the debugging mode   | Boolean value                                 |

#### 'Project' Example

```json
{
    "project": {
        "framework": "nest.js",
        "name": "Testing Project",
        "version": "1.0.0",
        "outDir": "src",
        "debugger": false,
        "database": "postgres"
    }
}
```

### The `schema` section

This sub-json is the core of your system, it is the one responsible for building your database schemas.

> Check the full API list for the schema section at the bottom of this page

#### 'Schema' Options

| Key       | Description                                  |
| --------- | -------------------------------------------- |
| tables    | Contains the tables, columns, and validators |
| relations | Contains relations among tables              |
| enums     | Contains the enums using in the columns      |

#### Example for the tables

```json
{
    "tables": {
        "tableOneName": {
            "propertyOneName": {
                "type": "string",
                "description": "",
                "defaultValue": "",
                "validations": {
                    "isRequired": true,
                    "maxLength": 25
                }
            }
        }
    }
}
```

#### Example for the relations

```json
{
    "relations": ["order<>item", "user>item", "user-profile"]
}
```

#### Example for the enums

```json
{
    "enums": {
        "enumOne": ["valueOne", "valueTwo"] // camel case strings
    }
}
```

### The `services` section

This sub-json controls the activation state of the **optional** services across the project:

#### 'Services' Options

| Key                       | Description                                                                   |
| ------------------------- | ----------------------------------------------------------------------------- |
| mailServiceIntegration    | Activate the mailing service to enable your project to send emails            |
| dockerizeApp              | Build the codes to dockerize the backend app & include dockersized DB         |

#### 'Services' Example

```json
{
    "services": {
        "mailServiceIntegration": true,
        "dockerizeApp": true,
    }
}
```

### The `env` section

This sub-json is reserved to store the keys in the env file needed for the project. When you change them from the config file, the keys will be changed in both the app and the env file.

> Note that we only control the keys here, you need to change the values manually from the `.env` file because the config file can't contain sensitive data since it will be pushed to the repo.

#### Options

| Key      | Env keys for                                   |
| -------- | ---------------------------------------------- |
| swagger  | The swagger implementation                     |
| jwt      | The JWT encryption specifications              |
| database | The database credentials and specifications    |
| mailer   | The mailing service credentials                |
| aws      | The AWS service credentials and specifications |

#### Example

```json
{
    "env": {
        "swagger": {
            "allowedUrls": "FRONTEND_URLS",
            "url": "ENVIRONMENT",
            "port": "PORT"
        },
        "jwt": {
            "secret": "JWT_SECRET"
        },
        "database": {
            "host": "DATABASE_HOST",
            "port": "DATABASE_PORT",
            "user": "POSTGRES_USER",
            "password": "POSTGRES_PASSWORD",
            "name": "POSTGRES_DB"
        },
        "mailer": {
            "email": "OFFICIAL_EMAIL",
            "password": "OFFICIAL_EMAIL_PASSWORD",
            "provider": "MAILER_SERVICE_PROVIDER"
        },
        "aws": {
            "accessKey": "AWS_ACCESS_KEY",
            "secretKey": "AWS_SECRET_ACCESS_KEY",
            "region": "AWS_REGION",
            "bucketName": "S3_BUCKET_NAME"
        }
    }
}
```

Check our detailed docs of how you can use the tool from here:

#### The `tables` Section

This sections defines the names of teh tables and columns for the schema. It also defines the specifications and validations for each column. Most types of fields are supported.

##### Tables listing and naming

You must list your tables' using their names as a series of keys inside the main sub-json `tables`, where the value of each key will have the table's columns.

You must name your tables in `snake_case` format using only alphabetic letters.

```json
{
    "tables": {
        "user": { ... },
        "item": { ... },
        "team_member": { ... },
        "order": { ... }
    }
}
```

##### Columns listing and naming

You must list your columns' using their names as a series of keys inside the related sub-json for their table, where the value of each key will have the column's specification and validations.

You must name your columns in `snake_case` format using only alphabetic letters.

```json
{
    "tables": {
        "user": {
            "first_name": { ... },
            "last_name": { ... },
            "email": { ... },
        }
    }
}
```

##### Columns specification and validations

###### **Specification**

- The `type` of the column can be one of these:

  - string
  - enum
  - number
  - array
  - object
  - date
  - time
  - boolean
  - file

- The `description` of the column is an optional string

- The `defaultValue` of the column is an optional string

###### **Any Column Validations**

| Key           | Type    | Description                                                        |
| ------------- | ------- | ------------------------------------------------------------------ |
| isRequired    | boolean | If true, the will be considered as required (can't be null)        |
| isUnique      | boolean | If true, the values must all be unique (no duplications)           |
| minLength     | number  | If set, the value must contains at least this number of characters |
| maxLength     | number  | If set, the value must contains at most this number of characters  |

###### **String Validations**

| Key           | Type    | Description                                                        |
| ------------- | ------- | ------------------------------------------------------------------ |
| isEmail       | boolean | If true, the value must be an email-like string                    |
| isUrl         | boolean | If true, the value must be a url-like string                       |
| isLatLong     | boolean | If true, the value must be a coordinations-like string             |
| isPhoneNumber | boolean | If true, the value must be a phone-number-like string              |
| enum          | string  | If set, the value must be one of that enum's values                |

###### **Numeric Validations**

| Key          | Type    | Description                                                 |
| ------------ | ------- | ----------------------------------------------------------- |
| isDecimal    | boolean | If true, the value must be decimal                          |
| isInteger    | boolean | If true, the value must be an integer                       |
| isPercentage | boolean | If true, the value must be a percentage (value from 0 to 1) |
| min          | number  | If set, the value must be at least this number              |
| max          | number  | If set, the value must be at most this number               |

###### **Example**

```json
{
    "tables": {
        "user": {
            "first_name": {
                "type": "string",
                "description": "The user fist name",
                "defaultValue": "my value",
                "validations": {
                    "isRequired": true,
                    "maxLength": 25
                }
            }
        }
    }
}
```

#### The `relations` Section

This section creates relation between the defined tables in the `tables` section. All types of relations are supported.

The relation is set by combining the two related tables names separated by a string annotating the relation type.

##### Relations Types

| Relation     | Separator | Example        | Meaning                                                                         |
| ------------ | :-------: | -------------- | ------------------------------------------------------------------------------- |
| One-To-One   |    `-`    | `user-profile` | Each user can only have one profile                                             |
| One-To-Many  |    `>`    | `user>item`    | Each user can have multiple items                                               |
| Many-To-Many |   `<>`    | `order<>item`  | Each order can have multiple items, and each item can belong to multiple orders |

##### Example

```json
{
    "relations": ["order<>item", "user>item", "user-profile"]
}
```

#### The `enums` Section

This section declares the enums you want to add to your columns. Any linked enum will add a validation to its column upon creating or updating any related record in the database.

You must list your enums using their names as a series of keys inside the related main sub-json for enums, where the value of each key will have an array of strings representing the possible values for each enum.

The names of each enum object must be in `PascalCase` format and each value must be in `snake_case` format using only **alphanumeric** letters

##### Example

```json
{
    "enums": {
        "enumOne": ["valueOne", "valueTwo"] // camel case strings
    }
}
```

## Specifications

### Directories

- The main file is supposed to be located at the root `./main.ts`
- The default used app directory is `./src/`
- Inside the app directory, we have organized and grouped directories for each section:
  - schemas
  - dto
  - enums
  - entities
  - decorators

### Naming

- The naming convention for all generated files is as follow:  
     `[name].[type].ts`
- Examples:
  - `app.module.ts`
  - `users.controller.ts`
  - `user-role.enum.ts`
  - `user.validator.ts`
  - `create-user.dto.ts`

## Limitations

### Language

Currently, the tool only generate codes in **TypeScript**

### Database

Currently, the only available database is **PostgreSQL**

### Storage

Currently, the only available storage integration option is **AWS S3 Bucket**

## Common Errors

### raven doesn't have permission on your terminal

- Open your terminal (steps for Ubuntu terminals)

- Open the `.bashrc` file using either VSCode or the terminal itself:

  - either: `code ~/.bashrc`
  - or: `nano ~/.bashrc`

- Provide permission to run raven by adding the following line at the end of the file **(after replacing the uppercase words with yours)**: `chmod +x /home/YOUR_USERNAME/.nvm/versions/node/YOUR_NODE_VERSION/bin/raven`

## Future Updates

- **To optionalize some of current features** will be available to use
- **Other DB Options** will be available to use
- **Other Storage Integration Options** will be available to use
- **Other Backend Framework Options** will be available to use
- **System Admin Panel** will be available to use
- **Auto generated comprehensive tests** will be available to use
- **Auto generated demo / development data seeders** will be available to use
- **Auto generated demo mode** will be available to use
- **Auto generated project technical documentation** will be available to use
- **Optional user-activity tracking feature** will be available to use
- **Optional DB / responses localization** will be available to use
- **Optional multi-tenant feature** will be available to use
- **Optional micro-service architecture implementation feature** will be available to use

## Development Team / Collaborators

- [Mustafa Hasanat](https://github.com/MustafaHasanat) Creator
- [Suhaib Ahmad](https://github.com/makkahwi) Main Contributor
