belt 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of belt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/belt/action_router.rb +13 -2
- data/lib/belt/cli/explain_command.rb +110 -0
- data/lib/belt/cli/frontend_env_command.rb +1 -1
- data/lib/belt/cli/frontend_env_map.rb +3 -1
- data/lib/belt/cli/lambda_config_command.rb +7 -2
- data/lib/belt/cli/routes_command.rb +24 -0
- data/lib/belt/cli.rb +4 -1
- data/lib/belt/docs/backups.md +101 -0
- data/lib/belt/docs/console.md +65 -0
- data/lib/belt/docs/controllers.md +155 -0
- data/lib/belt/docs/deployment.md +141 -0
- data/lib/belt/docs/generators.md +128 -0
- data/lib/belt/docs/lambda_handler.md +105 -0
- data/lib/belt/docs/models.md +160 -0
- data/lib/belt/docs/observability.md +94 -0
- data/lib/belt/docs/plugins.md +94 -0
- data/lib/belt/docs/routing.md +138 -0
- data/lib/belt/docs/structure.md +93 -0
- data/lib/belt/route_dsl.rb +17 -0
- data/lib/belt/version.rb +1 -1
- data/lib/templates/new_app/AGENTS.md.erb +140 -19
- data/lib/templates/new_app/config/routes.rb.erb +5 -2
- metadata +13 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Plugins
|
|
2
|
+
|
|
3
|
+
Belt plugins are separate gems that extend the CLI and runtime. They're
|
|
4
|
+
discovered automatically — no registration file or initializer hook needed.
|
|
5
|
+
|
|
6
|
+
## Using a Plugin
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
# Gemfile
|
|
10
|
+
gem "belt-messaging"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bundle install
|
|
15
|
+
belt generate messaging # run the plugin's generator
|
|
16
|
+
belt destroy messaging # remove what the generator created
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Available Plugins
|
|
20
|
+
|
|
21
|
+
| Gem | Purpose |
|
|
22
|
+
|-----|---------|
|
|
23
|
+
| `belt-messaging` | Two-way SMS via AWS End User Messaging |
|
|
24
|
+
| `belt-pay` | Stripe payments & subscriptions |
|
|
25
|
+
|
|
26
|
+
## Creating a Plugin
|
|
27
|
+
|
|
28
|
+
Scaffold a new plugin gem:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
belt plugin new notifications
|
|
32
|
+
belt plugin new pay --path ~/Code --summary "Stripe payments for Belt"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This creates a gem with the correct structure and Belt integration points.
|
|
36
|
+
|
|
37
|
+
## Plugin Discovery Contract
|
|
38
|
+
|
|
39
|
+
Belt discovers plugins automatically when:
|
|
40
|
+
|
|
41
|
+
1. Gem is in the app's `Gemfile` and bundled
|
|
42
|
+
2. Gem has a file at `lib/belt/generators/<name>_generator.rb`
|
|
43
|
+
3. Class is `Belt::Generators::<Name>Generator`
|
|
44
|
+
4. Class implements `.run(args)` (required)
|
|
45
|
+
|
|
46
|
+
Optional: `.destroy(args)` and `.description` for destroy path and help text.
|
|
47
|
+
|
|
48
|
+
## Generator Checklist
|
|
49
|
+
|
|
50
|
+
A good plugin generator typically installs:
|
|
51
|
+
|
|
52
|
+
1. **Terraform module** → `infrastructure/modules/<name>/`
|
|
53
|
+
2. **Lambda config** → `config/lambda/<name>.yml`
|
|
54
|
+
3. **Lambda entrypoint** → `lambda/<name>.rb` using `Belt::LambdaHandler`
|
|
55
|
+
4. **Routes / schema** → inject into routes or schema when needed
|
|
56
|
+
5. **Optional overrides** → `--controllers` flag for app-local subclasses
|
|
57
|
+
6. **Destroy path** → removes everything the generator created
|
|
58
|
+
7. **Help text** → `.description` + `--help`
|
|
59
|
+
|
|
60
|
+
## Plugin Layout
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
belt-messaging/
|
|
64
|
+
├── belt-messaging.gemspec
|
|
65
|
+
├── lib/
|
|
66
|
+
│ ├── belt-messaging.rb # require entrypoint
|
|
67
|
+
│ └── belt/
|
|
68
|
+
│ ├── messaging.rb # Runtime API
|
|
69
|
+
│ ├── messaging/
|
|
70
|
+
│ │ ├── configuration.rb
|
|
71
|
+
│ │ ├── version.rb
|
|
72
|
+
│ │ ├── controllers/ # Default controllers
|
|
73
|
+
│ │ └── templates/ # ERB templates for generator
|
|
74
|
+
│ └── generators/
|
|
75
|
+
│ └── messaging_generator.rb # ← auto-discovered
|
|
76
|
+
└── spec/
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Development Workflow
|
|
80
|
+
|
|
81
|
+
Point a Belt app at your plugin during development:
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
# In the app Gemfile
|
|
85
|
+
gem "belt-notifications", path: "../belt-notifications"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`belt deploy` detects `path:` gems and vendors them into `vendor/cache`
|
|
89
|
+
for Lambda packaging.
|
|
90
|
+
|
|
91
|
+
## See Also
|
|
92
|
+
|
|
93
|
+
- `belt explain generators` — built-in generators
|
|
94
|
+
- `belt plugin new --help` — scaffold options
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Routing
|
|
2
|
+
|
|
3
|
+
Belt routes map HTTP requests to controller actions. Routes are defined in
|
|
4
|
+
`config/routes.rb` using a Ruby DSL that mirrors infrastructure (API Gateway + Lambda).
|
|
5
|
+
|
|
6
|
+
## Defining Routes
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
Belt.application.routes.draw do
|
|
10
|
+
gateway :api do
|
|
11
|
+
resources :posts
|
|
12
|
+
resources :comments, only: [:index, :create]
|
|
13
|
+
resource :profile, only: [:show, :update]
|
|
14
|
+
get "health", action: :health
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Route DSL Keywords
|
|
20
|
+
|
|
21
|
+
| Keyword | Purpose | Creates Lambda? |
|
|
22
|
+
|---------|---------|-----------------|
|
|
23
|
+
| `gateway` | Creates an API Gateway + default Lambda | Yes |
|
|
24
|
+
| `function` | Routes to a different Lambda (overrides gateway default) | Yes |
|
|
25
|
+
| `namespace` | Adds path prefix + controller module nesting | No |
|
|
26
|
+
| `scope` | Flexible path/module/auth grouping | No |
|
|
27
|
+
|
|
28
|
+
## How `resources` Maps to Verbs
|
|
29
|
+
|
|
30
|
+
`resources :posts` generates:
|
|
31
|
+
|
|
32
|
+
| Verb | Path | Action |
|
|
33
|
+
|------|------|--------|
|
|
34
|
+
| GET | /posts | index |
|
|
35
|
+
| POST | /posts | create |
|
|
36
|
+
| GET | /posts/{post_id} | show |
|
|
37
|
+
| PUT | /posts/{post_id} | update |
|
|
38
|
+
| DELETE | /posts/{post_id} | destroy |
|
|
39
|
+
|
|
40
|
+
**Note:** Belt uses PUT, not PATCH, for updates.
|
|
41
|
+
|
|
42
|
+
Use `only:` or `except:` to limit generated routes:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
resources :posts, only: [:index, :show, :create]
|
|
46
|
+
resources :comments, except: [:destroy]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Singular Resources
|
|
50
|
+
|
|
51
|
+
`resource :profile` (no `:id` in the path):
|
|
52
|
+
|
|
53
|
+
| Verb | Path | Action |
|
|
54
|
+
|------|------|--------|
|
|
55
|
+
| GET | /profile | show |
|
|
56
|
+
| PUT | /profile | update |
|
|
57
|
+
| POST | /profile | create |
|
|
58
|
+
| DELETE | /profile | destroy |
|
|
59
|
+
|
|
60
|
+
## Namespace and Scope
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
gateway :api do
|
|
64
|
+
# Namespace: adds path prefix AND controller module
|
|
65
|
+
namespace :admin do
|
|
66
|
+
resources :users # → /admin/users → Admin::UsersController
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Scope: flexible grouping without full nesting
|
|
70
|
+
scope path: 'v2', module: 'legacy' do
|
|
71
|
+
resources :widgets # → /v2/widgets → Legacy::WidgetsController
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Multiple Lambdas
|
|
77
|
+
|
|
78
|
+
Use `function` when routes should be handled by a separate Lambda:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
gateway :api do
|
|
82
|
+
resources :posts # → handled by "api" Lambda
|
|
83
|
+
|
|
84
|
+
function :worker do
|
|
85
|
+
resources :jobs # → handled by "worker" Lambda
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Authentication
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
gateway :api, auth: :cognito do
|
|
94
|
+
resources :posts # requires cognito auth
|
|
95
|
+
get "health", action: :health, auth: :none # public
|
|
96
|
+
end
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Table Access
|
|
100
|
+
|
|
101
|
+
Declare which DynamoDB tables a route accesses (used by Terraform for IAM):
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
resources :posts, tables: [:posts, :comments]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Inspecting Routes
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
belt routes # display all routes
|
|
111
|
+
belt routes -g posts # filter by pattern
|
|
112
|
+
belt routes -f json # machine-readable output
|
|
113
|
+
belt routes --namespace api # generate Ruby route manifest
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Runtime Routing
|
|
117
|
+
|
|
118
|
+
The Lambda entry point uses `Belt::ActionRouter` with the generated route manifest:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
require "belt"
|
|
122
|
+
include Belt::LambdaHandler
|
|
123
|
+
|
|
124
|
+
ROUTER = Belt::ActionRouter.new(routes: Routes::API, gateway: "api")
|
|
125
|
+
|
|
126
|
+
def execute(path:, body:, event:)
|
|
127
|
+
ROUTER.route(event: event, body: body)
|
|
128
|
+
end
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The router matches the incoming HTTP method + path against the manifest and
|
|
132
|
+
dispatches to the appropriate controller and action.
|
|
133
|
+
|
|
134
|
+
## See Also
|
|
135
|
+
|
|
136
|
+
- `belt explain controllers` — how controllers handle requests
|
|
137
|
+
- `belt explain deployment` — how routes become infrastructure
|
|
138
|
+
- `belt routes --help` — full CLI options
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Project Structure
|
|
2
|
+
|
|
3
|
+
A Belt application follows a conventional directory layout. Understanding
|
|
4
|
+
this structure helps you navigate and extend the app effectively.
|
|
5
|
+
|
|
6
|
+
## Standard Layout
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
my-app/
|
|
10
|
+
├── lambda/ # Application code (deployed to Lambda)
|
|
11
|
+
│ ├── api.rb # Lambda entry point
|
|
12
|
+
│ ├── config/
|
|
13
|
+
│ │ └── environment.rb # App boot file (models, libs, AWS setup)
|
|
14
|
+
│ ├── controllers/
|
|
15
|
+
│ │ ├── application_controller.rb
|
|
16
|
+
│ │ └── my_app/ # Namespaced controllers
|
|
17
|
+
│ │ ├── posts_controller.rb
|
|
18
|
+
│ │ └── admin/
|
|
19
|
+
│ │ └── users_controller.rb
|
|
20
|
+
│ ├── models/
|
|
21
|
+
│ │ ├── application_record.rb # Base model class
|
|
22
|
+
│ │ ├── post.rb
|
|
23
|
+
│ │ └── concerns/ # Shared model behavior
|
|
24
|
+
│ ├── lib/
|
|
25
|
+
│ │ └── routes/ # Auto-generated route manifests
|
|
26
|
+
│ │ └── api_routes.rb
|
|
27
|
+
│ └── Gemfile # Lambda-specific dependencies
|
|
28
|
+
├── config/
|
|
29
|
+
│ ├── routes.rb # Route definitions (DSL)
|
|
30
|
+
│ ├── contracts.rb # API request/response contracts
|
|
31
|
+
│ └── lambda/ # Per-lambda configuration
|
|
32
|
+
│ └── api.yml # Timeout, memory, env vars
|
|
33
|
+
├── infrastructure/
|
|
34
|
+
│ ├── modules/ # Shared Terraform modules
|
|
35
|
+
│ │ └── main/
|
|
36
|
+
│ ├── schema.tf.rb # DynamoDB table schema (Ruby DSL)
|
|
37
|
+
│ ├── dev01/ # Per-environment Terraform
|
|
38
|
+
│ │ ├── main.tf
|
|
39
|
+
│ │ ├── variables.tf
|
|
40
|
+
│ │ ├── terraform.tfvars
|
|
41
|
+
│ │ ├── backend.tf
|
|
42
|
+
│ │ └── outputs.tf
|
|
43
|
+
│ └── prod/
|
|
44
|
+
│ └── ...
|
|
45
|
+
├── frontend/ # Optional frontend (React/Vue/Svelte)
|
|
46
|
+
├── Gemfile # Project-level dependencies (CLI, dev tools)
|
|
47
|
+
├── Rakefile # Rake tasks
|
|
48
|
+
├── AGENTS.md # AI agent guide
|
|
49
|
+
└── .gitignore
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Key Files
|
|
53
|
+
|
|
54
|
+
### `lambda/api.rb` — Lambda Entry Point
|
|
55
|
+
|
|
56
|
+
The file AWS Lambda invokes. Includes `Belt::LambdaHandler` and defines `execute`.
|
|
57
|
+
|
|
58
|
+
### `lambda/config/environment.rb` — Boot File
|
|
59
|
+
|
|
60
|
+
Loaded by both Lambda and `belt console`. Sets up AWS clients, requires models,
|
|
61
|
+
configures the app. Everything your app needs to run.
|
|
62
|
+
|
|
63
|
+
### `config/routes.rb` — Route Definitions
|
|
64
|
+
|
|
65
|
+
The Ruby DSL that defines your API. Read by both the Conveyor Belt Terraform
|
|
66
|
+
provider (for infrastructure) and `belt routes` (for manifests).
|
|
67
|
+
|
|
68
|
+
### `config/lambda/api.yml` — Lambda Config
|
|
69
|
+
|
|
70
|
+
Per-function settings: handler path, runtime, timeout, memory, environment
|
|
71
|
+
variables, layers, triggers.
|
|
72
|
+
|
|
73
|
+
### `infrastructure/schema.tf.rb` — Table Schema
|
|
74
|
+
|
|
75
|
+
DynamoDB table definitions in Ruby DSL. Used by `belt setup tables` to generate
|
|
76
|
+
Terraform resources.
|
|
77
|
+
|
|
78
|
+
## Conventions
|
|
79
|
+
|
|
80
|
+
- **Controller namespacing**: Controllers live under `lambda/controllers/<app_name>/`
|
|
81
|
+
to avoid conflicts across modules.
|
|
82
|
+
- **Route manifests**: Generated files in `lambda/lib/routes/` — don't edit manually.
|
|
83
|
+
Regenerate with `belt routes --namespace <name>`.
|
|
84
|
+
- **Two Gemfiles**: Project root Gemfile is for dev tools (belt CLI, rspec).
|
|
85
|
+
`lambda/Gemfile` is what gets packaged into the Lambda.
|
|
86
|
+
- **Config over code**: Lambda configuration (timeout, memory, env vars) goes in
|
|
87
|
+
YAML files, not hardcoded in Terraform.
|
|
88
|
+
|
|
89
|
+
## See Also
|
|
90
|
+
|
|
91
|
+
- `belt explain routing` — how routes.rb maps to infrastructure
|
|
92
|
+
- `belt explain controllers` — controller conventions
|
|
93
|
+
- `belt explain deployment` — how this structure gets deployed
|
data/lib/belt/route_dsl.rb
CHANGED
|
@@ -428,6 +428,23 @@ module Belt
|
|
|
428
428
|
end
|
|
429
429
|
end
|
|
430
430
|
|
|
431
|
+
# Rails-like `root` — defines a GET / route.
|
|
432
|
+
#
|
|
433
|
+
# Examples:
|
|
434
|
+
# root to: "welcome#show"
|
|
435
|
+
# root action: :show, controller: :welcome
|
|
436
|
+
# root "pages#home"
|
|
437
|
+
def root(options_or_target = nil, **options)
|
|
438
|
+
if options_or_target.is_a?(String)
|
|
439
|
+
options[:to] = options_or_target
|
|
440
|
+
elsif options_or_target.is_a?(Hash)
|
|
441
|
+
options = options_or_target.merge(options)
|
|
442
|
+
end
|
|
443
|
+
options[:auth] ||= :none
|
|
444
|
+
route_options = apply_scope_to_route(options)
|
|
445
|
+
@gateway.send(:get, '/', route_options)
|
|
446
|
+
end
|
|
447
|
+
|
|
431
448
|
def resources(name, options = {}, &)
|
|
432
449
|
options = apply_scope_options(options)
|
|
433
450
|
|
data/lib/belt/version.rb
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
This file explains the project structure, tooling, and conventions for AI agents working in this codebase.
|
|
4
4
|
|
|
5
|
+
## Quick Reference
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
belt explain <topic> # Get documentation on any Belt concept
|
|
9
|
+
belt explain routing # How routes work
|
|
10
|
+
belt explain controllers # Controller patterns and response helpers
|
|
11
|
+
belt explain models # ActiveItem (DynamoDB ORM)
|
|
12
|
+
belt explain deployment # Deploy lifecycle
|
|
13
|
+
belt explain generators # Scaffolding new resources
|
|
14
|
+
belt explain --help # List all available topics
|
|
15
|
+
```
|
|
16
|
+
|
|
5
17
|
## Stack
|
|
6
18
|
|
|
7
19
|
- **Belt** — CLI and runtime framework (like Rails for serverless). Provides Lambda handler, action router, controller base class, and CLI tooling.
|
|
@@ -33,6 +45,79 @@ This file explains the project structure, tooling, and conventions for AI agents
|
|
|
33
45
|
└── AGENTS.md # This file
|
|
34
46
|
```
|
|
35
47
|
|
|
48
|
+
## Common Tasks (Copy-Paste Recipes)
|
|
49
|
+
|
|
50
|
+
### Add a new REST resource
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
belt generate resource order item_id:string quantity:number total:number status:string
|
|
54
|
+
belt setup tables <env>
|
|
55
|
+
belt apply <env>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This creates: model, controller (with all CRUD actions), route entry, and DynamoDB schema.
|
|
59
|
+
|
|
60
|
+
### Add a model only (no API endpoint)
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
belt generate model audit_log user_id:string action:string resource:string
|
|
64
|
+
belt setup tables <env>
|
|
65
|
+
belt apply <env>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Add a controller only (route already exists)
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
belt generate controller admin/reports
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Add a new route to an existing resource
|
|
75
|
+
|
|
76
|
+
Edit `config/routes.rb`:
|
|
77
|
+
```ruby
|
|
78
|
+
# Inside the gateway block, add:
|
|
79
|
+
get "posts/search", controller: :posts, action: :search
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Then add the `search` action to `lambda/controllers/<%= @app_name %>/posts_controller.rb`.
|
|
83
|
+
|
|
84
|
+
### Deploy changes
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
belt deploy <env> # full deploy (init → plan → apply)
|
|
88
|
+
belt deploy <env> --auto # skip confirmation
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Inspect current routes
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
belt routes # human-readable table
|
|
95
|
+
belt routes -f json # machine-readable
|
|
96
|
+
belt routes -g posts # filter by pattern
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Open a console
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
belt c <env> # interactive Ruby session with app loaded
|
|
103
|
+
belt c <env> --run "Post.count" # one-liner
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Check system health
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
belt doctor # verify AWS creds, Terraform, Ruby, etc.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Add a new environment
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
belt generate environment staging
|
|
116
|
+
belt setup state # if no state bucket exists
|
|
117
|
+
belt setup tables staging
|
|
118
|
+
belt deploy staging
|
|
119
|
+
```
|
|
120
|
+
|
|
36
121
|
## Belt CLI Commands
|
|
37
122
|
|
|
38
123
|
```bash
|
|
@@ -43,12 +128,17 @@ belt generate controller <name> # Generate controller onl
|
|
|
43
128
|
belt generate environment <env_name> # Generate Terraform environment directory
|
|
44
129
|
belt setup state # Create/select S3 state bucket
|
|
45
130
|
belt setup tables <env> # Generate DynamoDB table definitions from schema
|
|
131
|
+
belt explain <topic> # Show documentation for a concept
|
|
46
132
|
belt init <env> # terraform init
|
|
47
133
|
belt plan <env> # terraform plan
|
|
48
134
|
belt apply <env> # terraform apply
|
|
49
135
|
belt destroy <env> # terraform destroy
|
|
50
|
-
belt destroy environment <env> # same (mirrors generate environment)
|
|
51
136
|
belt output <env> # terraform output
|
|
137
|
+
belt routes [-g PATTERN] [-f json] # Show route definitions
|
|
138
|
+
belt contracts [-g PATTERN] [-f json] # Show API contracts
|
|
139
|
+
belt console <env> # Interactive Ruby console
|
|
140
|
+
belt logs <lambda> [-f] [-s 5m] [-e env] # View Lambda logs
|
|
141
|
+
belt doctor # Check dependencies
|
|
52
142
|
```
|
|
53
143
|
|
|
54
144
|
## How Routing Works
|
|
@@ -62,12 +152,12 @@ belt output <env> # terraform output
|
|
|
62
152
|
end
|
|
63
153
|
```
|
|
64
154
|
|
|
65
|
-
2. Conveyor Belt creates
|
|
155
|
+
2. Conveyor Belt creates API Gateway routes. URLs look like:
|
|
66
156
|
```
|
|
67
157
|
https://api.<env>.example.com/<%= @app_name %>/things
|
|
68
158
|
```
|
|
69
159
|
|
|
70
|
-
3. The Lambda entry point (`lambda/<%= @app_name %>.rb`) uses `Belt::ActionRouter` to dispatch requests to controllers based on the route manifest
|
|
160
|
+
3. The Lambda entry point (`lambda/<%= @app_name %>.rb`) uses `Belt::ActionRouter` to dispatch requests to controllers based on the route manifest.
|
|
71
161
|
|
|
72
162
|
4. `resources :things` generates: `GET /things`, `POST /things`, `GET /things/:id`, `PUT /things/:id`, `DELETE /things/:id`. **PUT, not PATCH.**
|
|
73
163
|
|
|
@@ -83,7 +173,13 @@ end
|
|
|
83
173
|
|
|
84
174
|
Table names resolve as `{APP_NAME}-{ENVIRONMENT}-{pluralized_model}` (e.g., `<%= @app_name %>-wups-posts`).
|
|
85
175
|
|
|
86
|
-
Key
|
|
176
|
+
Key methods: `create!`, `find`, `find_by`, `where`, `update`, `destroy`, `all`, `count`, `exists?`.
|
|
177
|
+
|
|
178
|
+
Querying with indexes:
|
|
179
|
+
```ruby
|
|
180
|
+
Post.where(user_id: "u-123", index: "UserIndex")
|
|
181
|
+
Post.find_by(status: "active", index: "StatusIndex")
|
|
182
|
+
```
|
|
87
183
|
|
|
88
184
|
## How Controllers Work
|
|
89
185
|
|
|
@@ -93,24 +189,35 @@ Controllers inherit from `BeltController::Base`:
|
|
|
93
189
|
module <%= @module_name %>Controllers
|
|
94
190
|
class ThingsController < ApplicationController
|
|
95
191
|
def index
|
|
96
|
-
|
|
97
|
-
success_response(things: items.map(&:to_h))
|
|
192
|
+
@things = Thing.all # implicit JSON: { "things": [...] }
|
|
98
193
|
end
|
|
99
194
|
|
|
100
195
|
def show
|
|
101
|
-
|
|
102
|
-
success_response(thing: item.to_h)
|
|
196
|
+
@thing = Thing.find(params[:id]) # implicit JSON: { "thing": {...} }
|
|
103
197
|
end
|
|
104
198
|
|
|
105
199
|
def create
|
|
106
|
-
|
|
107
|
-
|
|
200
|
+
attrs = params.require(:thing).permit(:title, :content).to_h
|
|
201
|
+
@thing = Thing.create!(attrs)
|
|
202
|
+
response_status :created # 201 + implicit JSON
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def destroy
|
|
206
|
+
Thing.find(params[:id]).destroy
|
|
207
|
+
head :no_content # 204
|
|
108
208
|
end
|
|
109
209
|
end
|
|
110
210
|
end
|
|
111
211
|
```
|
|
112
212
|
|
|
113
|
-
|
|
213
|
+
**Key patterns:**
|
|
214
|
+
- `params` = merged path parameters + parsed JSON body
|
|
215
|
+
- Instance variables auto-serialize to JSON response
|
|
216
|
+
- `response_status :created` sets status without explicit response
|
|
217
|
+
- `head :no_content` for empty responses
|
|
218
|
+
- `success_response(data, status)` for explicit control
|
|
219
|
+
- `error_response(message, status)` for error responses
|
|
220
|
+
- `rescue_from` for exception handling
|
|
114
221
|
|
|
115
222
|
## Deployment Flow
|
|
116
223
|
|
|
@@ -119,16 +226,30 @@ export AWS_PROFILE=<your_profile>
|
|
|
119
226
|
belt setup state # One-time: create S3 state bucket
|
|
120
227
|
belt generate environment <env> # One-time: scaffold Terraform configs
|
|
121
228
|
belt setup tables <env> # Generate DynamoDB table resources
|
|
122
|
-
belt
|
|
123
|
-
belt apply <env> # Deploy everything
|
|
229
|
+
belt deploy <env> # Deploy everything (init → plan → apply)
|
|
124
230
|
```
|
|
125
231
|
|
|
126
|
-
##
|
|
232
|
+
## Key Differences from Rails
|
|
233
|
+
|
|
234
|
+
| Rails | Belt |
|
|
235
|
+
|-------|------|
|
|
236
|
+
| PostgreSQL / MySQL | DynamoDB (NoSQL) |
|
|
237
|
+
| ActiveRecord | ActiveItem |
|
|
238
|
+
| `PATCH` for updates | `PUT` for updates |
|
|
239
|
+
| `rails server` | Deployed to AWS Lambda |
|
|
240
|
+
| `rails routes` | `belt routes` |
|
|
241
|
+
| `rails console` | `belt console <env>` |
|
|
242
|
+
| `config/routes.rb` → URL paths | `config/routes.rb` → URL paths + infrastructure |
|
|
243
|
+
| Migrations | `belt setup tables <env>` |
|
|
244
|
+
| `has_many` / `belongs_to` | Manual (no joins in DynamoDB) |
|
|
245
|
+
| Template rendering | JSON responses (default) |
|
|
246
|
+
|
|
247
|
+
## Troubleshooting
|
|
127
248
|
|
|
128
249
|
```bash
|
|
129
|
-
belt
|
|
130
|
-
belt
|
|
131
|
-
belt
|
|
250
|
+
belt doctor # Check all dependencies
|
|
251
|
+
belt explain <topic> # Documentation for any concept
|
|
252
|
+
belt routes -f json # Verify route configuration
|
|
253
|
+
belt logs <lambda> -e <env> -s 5m # Check recent Lambda logs
|
|
254
|
+
belt c <env> --run "Post.count" # Verify data access
|
|
132
255
|
```
|
|
133
|
-
|
|
134
|
-
This creates the model, controller, updates routes + schema, generates the DynamoDB table definition, and deploys.
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
Belt.application.routes.draw do
|
|
2
4
|
# Creates an API Gateway named "api" with a default Lambda function of the same name.
|
|
3
5
|
# Use `function :other_name do ... end` inside to route specific paths to additional Lambdas.
|
|
4
6
|
gateway :api do
|
|
5
|
-
# Public stack-check / welcome (HTML for browsers, JSON for the SPA shell)
|
|
6
|
-
|
|
7
|
+
# Public stack-check / welcome (HTML for browsers, JSON for the SPA shell).
|
|
8
|
+
# This route is auto-injected by Belt if omitted, but keeping it explicit is clearer.
|
|
9
|
+
root to: 'welcome#show'
|
|
7
10
|
# resources :posts
|
|
8
11
|
end
|
|
9
12
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: belt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stowzilla
|
|
@@ -116,6 +116,7 @@ files:
|
|
|
116
116
|
- lib/belt/cli/env_resolver.rb
|
|
117
117
|
- lib/belt/cli/environment_command.rb
|
|
118
118
|
- lib/belt/cli/environment_config.rb
|
|
119
|
+
- lib/belt/cli/explain_command.rb
|
|
119
120
|
- lib/belt/cli/frontend_command.rb
|
|
120
121
|
- lib/belt/cli/frontend_deploy_command.rb
|
|
121
122
|
- lib/belt/cli/frontend_env_command.rb
|
|
@@ -140,6 +141,17 @@ files:
|
|
|
140
141
|
- lib/belt/cli/views_command.rb
|
|
141
142
|
- lib/belt/configuration.rb
|
|
142
143
|
- lib/belt/controllers/welcome_controller.rb
|
|
144
|
+
- lib/belt/docs/backups.md
|
|
145
|
+
- lib/belt/docs/console.md
|
|
146
|
+
- lib/belt/docs/controllers.md
|
|
147
|
+
- lib/belt/docs/deployment.md
|
|
148
|
+
- lib/belt/docs/generators.md
|
|
149
|
+
- lib/belt/docs/lambda_handler.md
|
|
150
|
+
- lib/belt/docs/models.md
|
|
151
|
+
- lib/belt/docs/observability.md
|
|
152
|
+
- lib/belt/docs/plugins.md
|
|
153
|
+
- lib/belt/docs/routing.md
|
|
154
|
+
- lib/belt/docs/structure.md
|
|
143
155
|
- lib/belt/helpers/cors_origin.rb
|
|
144
156
|
- lib/belt/helpers/error_logging.rb
|
|
145
157
|
- lib/belt/helpers/response.rb
|