feat: Initial observations endpoint
This commit is contained in:
228
AGENTS.md
Normal file
228
AGENTS.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# AGENTS.md - Yockboard Development Guide
|
||||
|
||||
This document provides guidelines for agentic coding agents working on the Yockboard Rails application.
|
||||
|
||||
## Project Overview
|
||||
|
||||
- **Framework**: Ruby on Rails 8.1.2
|
||||
- **Ruby Version**: 3.4.7
|
||||
- **Database**: PostgreSQL
|
||||
- **Testing**: Minitest (Rails default)
|
||||
- **JavaScript**: Turbo + Stimulus with Importmap
|
||||
|
||||
## Build / Lint / Test Commands
|
||||
|
||||
### Development Server
|
||||
```bash
|
||||
./bin/dev # Start development server (alias for bin/rails server)
|
||||
bin/rails server -p 3000
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
```bash
|
||||
# Run all tests
|
||||
bin/rails test
|
||||
|
||||
# Run a single test file
|
||||
bin/rails test test/models/user_test.rb
|
||||
|
||||
# Run a single test by name
|
||||
bin/rails test test/models/user_test.rb -n test_user_validity
|
||||
|
||||
# Run system tests (browser-based)
|
||||
bin/rails test:system
|
||||
|
||||
# Run tests in specific directory
|
||||
bin/rails test test/controllers/
|
||||
```
|
||||
|
||||
### Linting & Code Style
|
||||
```bash
|
||||
# Run RuboCop linter
|
||||
bin/rubocop
|
||||
|
||||
# Run specific RuboCop check
|
||||
bin/rubocop app/models/
|
||||
|
||||
# Auto-fix RuboCop issues
|
||||
bin/rubocop -a
|
||||
```
|
||||
|
||||
### Security Scanning
|
||||
```bash
|
||||
# Scan for Rails security vulnerabilities
|
||||
bin/brakeman --no-pager
|
||||
|
||||
# Scan for known gem vulnerabilities
|
||||
bin/bundler-audit
|
||||
|
||||
# Audit JS dependencies
|
||||
bin/importmap audit
|
||||
```
|
||||
|
||||
### Database
|
||||
```bash
|
||||
bin/rails db:create db:migrate # Setup database
|
||||
bin/rails db:test:prepare # Prepare test database
|
||||
bin/rails db:reset # Reset database
|
||||
```
|
||||
|
||||
### CI Pipeline (in .github/workflows/ci.yml)
|
||||
- `scan_ruby`: Brakeman + bundler-audit
|
||||
- `scan_js`: Importmap audit
|
||||
- `lint`: RuboCop
|
||||
- `test`: Full test suite with PostgreSQL
|
||||
- `system-test`: System/integration tests
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### General Philosophy
|
||||
Follow the **Rails Omakase** style (via `rubocop-rails-omakase`). This is the default Rails team style.
|
||||
|
||||
### File Organization
|
||||
- Models: `app/models/`
|
||||
- Controllers: `app/controllers/`
|
||||
- Views: `app/views/controller_name/`
|
||||
- Helpers: `app/helpers/`
|
||||
- Jobs: `app/jobs/`
|
||||
- Mailers: `app/mailers/`
|
||||
|
||||
### Naming Conventions
|
||||
- **Classes/Modules**: `PascalCase` (e.g., `UserAccount`, `OrderProcessor`)
|
||||
- **Database tables**: `snake_case_plurals` (e.g., `user_accounts`, `orders`)
|
||||
- **Files**: `snake_case.rb` (e.g., `user_account.rb`, `order_processor.rb`)
|
||||
- **Methods/variables**: `snake_case` (e.g., `user_accounts`, `process_order`)
|
||||
- **Boolean methods**: End with `?` (e.g., `valid?`, `confirmed?`)
|
||||
- **Bang methods**: End with `!` for mutating variants (e.g., `save!`, `update!`)
|
||||
- **Query methods**: End with `?` or use plural names (e.g., `admin?`, `users`)
|
||||
|
||||
### Routing
|
||||
- Use RESTful routes with `resources` when applicable
|
||||
- Use namespace for admin/API routes
|
||||
- Prefer shallow nesting: `resources :posts, shallow: true do resources :comments end`
|
||||
|
||||
### Models
|
||||
- Inherit from `ApplicationRecord`
|
||||
- Use concerns for shared behavior in `app/models/concerns/`
|
||||
- Define associations explicitly
|
||||
- Use scopes for common queries
|
||||
|
||||
```ruby
|
||||
class User < ApplicationRecord
|
||||
has_many :posts, dependent: :destroy
|
||||
|
||||
scope :active, -> { where(active: true) }
|
||||
|
||||
def full_name
|
||||
"#{first_name} #{last_name}".strip
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Controllers
|
||||
- Inherit from `ApplicationController`
|
||||
- Use strong parameters for mass assignment
|
||||
- Follow RESTful actions pattern
|
||||
- Keep controllers thin; push logic to models/services
|
||||
|
||||
```ruby
|
||||
class UsersController < ApplicationController
|
||||
def index
|
||||
@users = User.active.order(:created_at)
|
||||
end
|
||||
|
||||
def create
|
||||
@user = User.new(user_params)
|
||||
if @user.save
|
||||
redirect_to @user, notice: "User created"
|
||||
else
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:first_name, :last_name, :email)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Views
|
||||
- Use ERB with HTML
|
||||
- Use Turbo Frames/Streams for SPA-like behavior
|
||||
- Prefer Stimulus controllers over vanilla JS
|
||||
- Use partials for reusable components
|
||||
|
||||
### Testing (Minitest)
|
||||
- Test files go in `test/` mirroring `app/` structure
|
||||
- Use `test/test_helper.rb` for shared setup
|
||||
- Use fixtures in `test/fixtures/` for test data
|
||||
|
||||
```ruby
|
||||
require "test_helper"
|
||||
|
||||
class UserTest < ActiveSupport::TestCase
|
||||
test "valid user" do
|
||||
user = User.new(email: "test@example.com", name: "Test")
|
||||
assert user.valid?
|
||||
end
|
||||
|
||||
test "invalid without email" do
|
||||
user = User.new(name: "Test")
|
||||
assert_not user.valid?
|
||||
assert_includes user.errors[:email], "must be present"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
- Use ` rescue` blocks for expected errors
|
||||
- Use `fail` or `raise` for unexpected states
|
||||
- Flash messages for user feedback
|
||||
- Render appropriate HTTP status codes
|
||||
|
||||
### Database
|
||||
- Use migrations for schema changes: `bin/rails generate migration AddFieldToTable`
|
||||
- Use `change` method for reversible migrations
|
||||
- Add indexes for foreign keys and frequently queried columns
|
||||
|
||||
### Dependencies
|
||||
- Add gems to appropriate groups in `Gemfile`
|
||||
- Run `bundle install` after adding gems
|
||||
- Use `Gemfile.lock` for reproducible builds
|
||||
|
||||
### Git Conventions
|
||||
- Write clear, concise commit messages
|
||||
- Create feature branches for new work
|
||||
- Run linter and tests before committing
|
||||
|
||||
## Important File Locations
|
||||
|
||||
- Routes: `config/routes.rb`
|
||||
- Application config: `config/application.rb`
|
||||
- Environment configs: `config/environments/`
|
||||
- Database config: `config/database.yml`
|
||||
- Test config: `test/test_helper.rb`
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Generate New Resource
|
||||
```bash
|
||||
bin/rails generate scaffold ModelName field:type field:type
|
||||
bin/rails db:migrate
|
||||
```
|
||||
|
||||
### Run Specific Gem Command
|
||||
```bash
|
||||
bundle exec brakeman --no-pager
|
||||
bundle exec rubocop
|
||||
bundle exec rails test
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- This project uses **Solid** gems for cache/queue/cable (SolidCache, SolidQueue, SolidCable)
|
||||
- Asset pipeline: Propshaft (Rails 8 default)
|
||||
- JS: Importmap with Turbo and Stimulus
|
||||
- Deployment: Kamal (see `.kamal/`)
|
||||
7
app/controllers/api/api_controller.rb
Normal file
7
app/controllers/api/api_controller.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
class APIController < ApplicationController
|
||||
skip_forgery_protection
|
||||
end
|
||||
end
|
||||
15
app/controllers/api/v1/weather/observations_controller.rb
Normal file
15
app/controllers/api/v1/weather/observations_controller.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V1
|
||||
module Weather
|
||||
class ObservationsController < APIController
|
||||
def create
|
||||
Rails.logger.debug 'Create new observation'
|
||||
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
# Name of your application. Used to uniquely configure containers.
|
||||
# Name of your application. Used to uniquely configure containers.deploy
|
||||
service: yockboard
|
||||
|
||||
# Name of the container image (use your-user/app-name on external registries).
|
||||
@@ -7,7 +7,7 @@ image: yockboard
|
||||
# Deploy to these servers.
|
||||
servers:
|
||||
web:
|
||||
- 192.168.0.1
|
||||
- 103.163.186.137
|
||||
# job:
|
||||
# hosts:
|
||||
# - 192.168.0.1
|
||||
@@ -20,9 +20,9 @@ servers:
|
||||
#
|
||||
# Don't use this when deploying to multiple web servers (then you have to terminate SSL at your load balancer).
|
||||
#
|
||||
# proxy:
|
||||
# ssl: true
|
||||
# host: app.example.com
|
||||
proxy:
|
||||
ssl: true
|
||||
host: yockboard.yock.dev
|
||||
|
||||
# Where you keep your container images.
|
||||
registry:
|
||||
@@ -41,6 +41,7 @@ env:
|
||||
secret:
|
||||
- RAILS_MASTER_KEY
|
||||
clear:
|
||||
PORT: 3005
|
||||
# Run the Solid Queue Supervisor inside the web server's Puma process to do jobs.
|
||||
# When you start using multiple servers, you should split out job processing to a dedicated machine.
|
||||
SOLID_QUEUE_IN_PUMA: true
|
||||
|
||||
@@ -2,6 +2,9 @@ require "active_support/core_ext/integer/time"
|
||||
|
||||
Rails.application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
config.hosts = [
|
||||
"yockboard.yock.dev", # Allow requests from example.com
|
||||
]
|
||||
|
||||
# Make code changes take effect immediately without server restart.
|
||||
config.enable_reloading = true
|
||||
|
||||
@@ -80,10 +80,9 @@ Rails.application.configure do
|
||||
config.active_record.attributes_for_inspect = [ :id ]
|
||||
|
||||
# Enable DNS rebinding protection and other `Host` header attacks.
|
||||
# config.hosts = [
|
||||
# "example.com", # Allow requests from example.com
|
||||
# /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
|
||||
# ]
|
||||
config.hosts = [
|
||||
"yockboard.yock.dev", # Allow requests from example.com
|
||||
]
|
||||
#
|
||||
# Skip DNS rebinding protection for the default health check endpoint.
|
||||
# config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
# end
|
||||
|
||||
# These inflection rules are supported but not enabled by default:
|
||||
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
||||
# inflect.acronym "RESTful"
|
||||
# end
|
||||
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
||||
inflect.acronym 'API'
|
||||
end
|
||||
|
||||
@@ -11,4 +11,12 @@ Rails.application.routes.draw do
|
||||
|
||||
# Defines the root path route ("/")
|
||||
# root "posts#index"
|
||||
|
||||
namespace :api do
|
||||
namespace :v1 do
|
||||
namespace :weather do
|
||||
resources :observations
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
8
db/migrate/20260216224032_create_observations.rb
Normal file
8
db/migrate/20260216224032_create_observations.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
class CreateObservations < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
create_table :observations do |t|
|
||||
t.jsonb :request_body
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
22
db/schema.rb
generated
Normal file
22
db/schema.rb
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
# This file is auto-generated from the current state of the database. Instead
|
||||
# of editing this file, please use the migrations feature of Active Record to
|
||||
# incrementally modify your database, and then regenerate this schema definition.
|
||||
#
|
||||
# This file is the source Rails uses to define your schema when running `bin/rails
|
||||
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
||||
# be faster and is potentially less error prone than running all of your
|
||||
# migrations from scratch. Old migrations may fail to apply correctly if those
|
||||
# migrations use external dependencies or application code.
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.1].define(version: 2026_02_16_224032) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_catalog.plpgsql"
|
||||
|
||||
create_table "observations", force: :cascade do |t|
|
||||
t.datetime "created_at", null: false
|
||||
t.jsonb "request_body"
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user