# Rebar3 plugin for Nova
=====
A rebar plugin for nova
## Build
$ rebar3 compile
## Installation
Add the plugin to your rebar config (`~/.config/rebar3/rebar.config`):
{plugins, [
{rebar3_nova, {git, "https://github.com/novaframework/rebar3_nova.git", {branch, "master"}}}
]}.
For latest stable from hex:
{plugins, [rebar3_nova]}.
Then just call your plugin directly in an existing application:
$ rebar3 nova
===> Fetching rebar3_nova
===> Compiling rebar3_nova
## Commands
### `nova serve` — Auto-reload development server
Starts the application with auto-reload. Source file changes are automatically compiled and hot-loaded.
```
$ rebar3 nova serve
```
### `nova routes` — List compiled routes
Displays the compiled routing tree with methods, paths, and handler modules.
```
$ rebar3 nova routes
```
### `nova gen_controller` — Generate a controller
Scaffolds a controller module with stub functions for CRUD actions.
```
$ rebar3 nova gen_controller --name users
===> Created src/controllers/myapp_users_controller.erl
$ rebar3 nova gen_controller --name users --actions list,show
===> Created src/controllers/myapp_users_controller.erl
```
**Options:**
| Flag | Required | Default | Description |
|------|----------|---------|-------------|
| `--name`, `-n` | yes | — | Controller name |
| `--actions`, `-a` | no | `list,show,create,update,delete` | Comma-separated actions to generate |
Generated functions return stub responses:
- `list/1`, `show/1`, `update/1` return `{json, #{<<"message">> => <<"TODO">>}}`
- `create/1` returns `{status, 201, #{}, #{<<"message">> => <<"TODO">>}}`
- `delete/1` returns `{status, 204}`
If the file already exists, the command skips it with a warning.
### `nova gen_resource` — Generate a full resource
Combines controller generation, JSON schema creation, and prints route snippets to add to your router.
```
$ rebar3 nova gen_resource --name products
===> Created src/controllers/myapp_products_controller.erl
===> Created priv/schemas/product.json
===>
===> Add these routes to your router:
===> {<<"/products">>, {myapp_products_controller, list}, #{methods => [get]}}
===> {<<"/products/:id">>, {myapp_products_controller, show}, #{methods => [get]}}
===> {<<"/products">>, {myapp_products_controller, create}, #{methods => [post]}}
===> {<<"/products/:id">>, {myapp_products_controller, update}, #{methods => [put]}}
===> {<<"/products/:id">>, {myapp_products_controller, delete}, #{methods => [delete]}}
```
**Options:** Same as `gen_controller`.
The JSON schema is placed in `priv/schemas/{singular}.json` with `id` and `name` fields as a starting point. The resource name is naively singularized by stripping a trailing "s".
### `nova gen_test` — Generate a Common Test suite
Scaffolds a CT suite with test cases for CRUD actions using `httpc`.
```
$ rebar3 nova gen_test --name users
===> Created test/myapp_users_controller_SUITE.erl
```
**Options:**
| Flag | Required | Default | Description |
|------|----------|---------|-------------|
| `--name`, `-n` | yes | — | Resource name |
The generated suite starts `inets` and the application in `init_per_suite`, then tests each CRUD endpoint against `http://localhost:8080/{name}`.
### `nova openapi` — Generate OpenAPI 3.0.3 spec
Generates an OpenAPI 3.0.3 JSON specification from compiled routes and any JSON schemas found in `priv/schemas/`.
```
$ rebar3 nova openapi
===> OpenAPI spec written to /path/to/myapp/priv/assets/openapi.json
===> Swagger UI written to /path/to/myapp/priv/assets/swagger.html
$ rebar3 nova openapi --title "My API" --api-version 1.0.0
$ rebar3 nova openapi --output custom/path/openapi.json
```
**Options:**
| Flag | Required | Default | Description |
|------|----------|---------|-------------|
| `--output`, `-o` | no | `priv/assets/openapi.json` | Output file path |
| `--title`, `-t` | no | app name | API title |
| `--api-version`, `-v` | no | `0.1.0` | API version string |
A `swagger.html` file is also generated alongside the spec for quick browser-based exploration. The output directory is created automatically if it doesn't exist.
### `nova middleware` — Show plugin/middleware chains
Displays global plugins and per-route-group plugin chains, preserving the grouping defined in your router's `routes/1` function.
```
$ rebar3 nova middleware
=== Global Plugins ===
(none)
=== Route Groups (myapp_router) ===
Group: prefix=/ security=false
Plugins:
(inherits global: none)
Routes:
GET /heartbeat -> myapp_health_controller:heartbeat
GET /health -> myapp_health_controller:health
Group: prefix=/api security=fun myapp_auth:validate_token/1
Plugins:
pre_request: nova_cors_plugin #{allow_origins => <<"*">>}
pre_request: nova_request_logger #{level => info}
Routes:
GET /users -> myapp_users_controller:list
POST /users -> myapp_users_controller:create
```
Groups that don't specify their own `plugins` key inherit from the global Nova plugin configuration.
### `nova config` — Show Nova configuration
Displays all Nova configuration keys read from `sys.config`, showing current values or `(default)` when using built-in defaults.
```
$ rebar3 nova config
=== Nova Configuration ===
bootstrap_application myapp
environment dev
cowboy_configuration #{port => 8080} (default)
plugins [] (default)
json_lib thoas (default)
use_stacktrace false (default)
dispatch_backend persistent_term (default)
```
Warns if `bootstrap_application` is not set.
### `nova audit` — Audit route security
Checks compiled routes for common security issues and prints findings grouped by severity.
```
$ rebar3 nova audit
=== Security Audit ===
WARNINGS:
POST /users (myapp_users_controller) has no security
PUT /users/1 (myapp_users_controller) has no security
DELETE /users/1 (myapp_users_controller) has no security
INFO:
GET /users (myapp_users_controller) has no security
GET /health (myapp_health_controller) has no security
Summary: 3 warning(s), 2 info(s)
```
**Rules checked:**
- **Warning**: Mutation methods (POST, PUT, DELETE, PATCH) without a security callback
- **Warning**: Wildcard method (`'_'`) matching all HTTP methods on a route
- **Info**: GET routes without a security callback
### `nova release` — Build a release
Wraps the standard rebar3 release provider. If `priv/schemas/` exists, regenerates the OpenAPI spec before building.
```
$ rebar3 nova release
===> Regenerating OpenAPI spec...
===> Release built successfully with profile 'prod'
$ rebar3 nova release --profile staging
```
**Options:**
| Flag | Required | Default | Description |
|------|----------|---------|-------------|
| `--profile`, `-p` | no | `prod` | Release profile to use |