Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env → .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ MONGO_DB_NAME=chain_forge
MONGO_DB_PORT=27017
MONGO_DB_HOST=localhost
ENVIRONMENT=development
DEFAULT_DIFFICULTY=2
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ MONGO_DB_NAME=chain_forge_test
MONGO_DB_PORT=27017
MONGO_DB_HOST=localhost
ENVIRONMENT=test
DEFAULT_DIFFICULTY=2
266 changes: 131 additions & 135 deletions .junie/guidelines.md
Original file line number Diff line number Diff line change
@@ -1,158 +1,154 @@
# ChainForge — Development Guidelines
### ChainForge — Dev Guidelines (verified 2025-11-09 22:57 local)

This document captures project-specific practices for building, testing, and extending ChainForge. It assumes an advanced Ruby developer familiar with Bundler, RSpec, Docker, and MongoDB.
These notes capture project-specific setup, testing, and dev practices validated on a clean environment with Docker-provided MongoDB.

## Build and Configuration
#### Tech stack
- Ruby 3.2.2 (Bundler 2.4.13)
- Sinatra 4.x, Mongoid 7.0.x, MongoDB
- RSpec, SimpleCov, RuboCop (+ rubocop-rspec)
- dotenv for env loading; Rack::Attack middleware (disabled in test)

- Ruby: 3.2.2 (see `Gemfile` and `Dockerfile`).
- App stack: Sinatra 4.x, Mongoid 7.0.x, MongoDB.
- Environment configuration is consumed via `dotenv` and `Mongoid`:
- `Mongoid.load!('./config/mongoid.yml', ENV['ENVIRONMENT'] || :development)` in `main.rb`
- `Mongoid.load!('./config/mongoid.yml', ENV['ENVIRONMENT'] || :test)` in `spec/spec_helper.rb`
- Required ENV (both development and test environments):
- `ENVIRONMENT` — one of `development` or `test` (symbol allowed by Mongoid). Defaults to `development` in app, `test` in specs when unset.
- `MONGO_DB_NAME` — database name (e.g., `chain_forge_dev` or `chain_forge_test`).
- `MONGO_DB_HOST` — MongoDB host (e.g., `127.0.0.1`).
- `MONGO_DB_PORT` — MongoDB port (e.g., `27017`).
- Mongoid config (`config/mongoid.yml`) uses only these ENV variables (no auth block). Ensure the vars are set or use Docker.

### Installing dependencies

```bash
# Ruby 3.2.2 assumed
gem install bundler -v 2.4.13
bundle install
```

### Running via Docker (recommended for a clean Mongo)

```bash
docker-compose up -d
# Exposes app on :1910 and mongo on :27017 by default
```

### Running app locally

```bash
# Ensure MongoDB is reachable at MONGO_DB_HOST:MONGO_DB_PORT and DB exists/auto-creates
ENVIRONMENT=development \
MONGO_DB_NAME=chain_forge_dev \
MONGO_DB_HOST=127.0.0.1 \
MONGO_DB_PORT=27017 \
bundle exec ruby main.rb -p 1910
```

## Testing

RSpec is configured in `spec/spec_helper.rb` and loads Mongoid in `:test` unless `ENVIRONMENT` overrides.

### Baseline run (verified)

The following has been verified to pass for unit-level specs on a fresh run with MongoDB available (e.g., via `docker-compose up -d`):

```bash
ENVIRONMENT=test \
MONGO_DB_NAME=chain_forge_test \
MONGO_DB_HOST=127.0.0.1 \
MONGO_DB_PORT=27017 \
bundle exec rspec spec/block_spec.rb spec/blockchain_spec.rb
```

Notes:
- The full suite currently includes API specs that may fail depending on content-type behavior and rack/test expectations. If you want green runs while iterating on models, scope to the unit specs above or filter via `-e/--example` or `--pattern`.
- Full-suite run example (may include failing API specs today):
---

```bash
ENVIRONMENT=test MONGO_DB_NAME=chain_forge_test MONGO_DB_HOST=127.0.0.1 MONGO_DB_PORT=27017 \
bundle exec rspec
```
### Build & Configuration

### Focused runs and filters
- Install deps (verified):
```bash
gem install bundler -v 2.4.13
bundle install
```

- Single file: `bundle exec rspec spec/block_spec.rb`
- Single example: `bundle exec rspec spec/block_spec.rb:37`
- By example name: `bundle exec rspec -e 'validates the blockchain'`
- Required env vars (used by `config/mongoid.yml`):
- `ENVIRONMENT` — `development` or `test`. Defaults: app → `development`; specs set `test` in `spec/spec_helper.rb`.
- `MONGO_DB_NAME` — DB name (e.g., `chain_forge_dev`, `chain_forge_test`).
- `MONGO_DB_HOST` — Mongo host (e.g., `127.0.0.1` or `db` inside compose).
- `MONGO_DB_PORT` — Mongo port (e.g., `27017`).

### Coverage
- Mongoid loading points:
- App: `Mongoid.load!("./config/mongoid.yml", ENV['ENVIRONMENT'] || :development)` in `main.rb`.
- Specs: `Mongoid.load!("./config/mongoid.yml", :test)` in `spec/spec_helper.rb` (and `ENV['ENVIRONMENT']='test'`).

SimpleCov is available (loaded on demand). To enable coverage, set an env var before running:
- Docker (recommended for a clean Mongo):
```bash
docker-compose up -d
# Exposes app on :1910 and Mongo on :27017
```
- Service names: `app`, `db`. The app uses `ruby main.rb -p 1910` per `Dockerfile`.

```bash
COVERAGE=true ENVIRONMENT=test MONGO_DB_NAME=chain_forge_test MONGO_DB_HOST=127.0.0.1 MONGO_DB_PORT=27017 \
bundle exec rspec
# Coverage report will be in coverage/index.html
```
- Run app locally (outside Docker):
```bash
ENVIRONMENT=development \
MONGO_DB_NAME=chain_forge_dev \
MONGO_DB_HOST=127.0.0.1 \
MONGO_DB_PORT=27017 \
bundle exec ruby main.rb -p 1910
```
- Note: `before` block in `main.rb` sets `content_type :json` for POSTs; the root route sets `:html` explicitly.
- Rack::Attack is enabled except when `ENVIRONMENT=test`.

### Adding a new spec (demonstrated workflow)
---

The following process was executed and verified end-to-end; replicate as needed:
### Testing

1. Create a new spec file under `spec/`, e.g. `spec/demo_math_spec.rb`:
```ruby
# frozen_string_literal: true
require 'rspec'
- Verified baseline (unit-level specs only):
```bash
ENVIRONMENT=test \
MONGO_DB_NAME=chain_forge_test \
MONGO_DB_HOST=127.0.0.1 \
MONGO_DB_PORT=27017 \
bundle exec rspec spec/block_spec.rb spec/blockchain_spec.rb
```
Result observed: 10 examples, 0 failures.

RSpec.describe 'Math demo' do
it 'adds numbers' do
expect(1 + 1).to eq(2)
- Full suite:
```bash
ENVIRONMENT=test MONGO_DB_NAME=chain_forge_test MONGO_DB_HOST=127.0.0.1 MONGO_DB_PORT=27017 \
bundle exec rspec
```
Note: API specs (`spec/api_spec.rb`) may be sensitive to content-type behavior or rack/test mounting. The app sets JSON content-type for POSTs globally and again in the `/api/v1` namespace, which generally aligns with expectations.

- Focused runs and filters:
- Single file: `bundle exec rspec spec/block_spec.rb`
- Single example: `bundle exec rspec spec/block_spec.rb:37`
- By name: `bundle exec rspec -e 'validates the blockchain'`

- Adding a new spec (workflow verified end-to-end):
1) Create a file, e.g. `spec/demo_math_spec.rb`:
```ruby
# frozen_string_literal: true
require 'rspec'

RSpec.describe 'Math demo' do
it 'adds numbers' do
expect(1 + 1).to eq(2)
end
end
end
```
2. Run just that spec:
```bash
ENVIRONMENT=test MONGO_DB_NAME=chain_forge_test MONGO_DB_HOST=127.0.0.1 MONGO_DB_PORT=27017 \
bundle exec rspec spec/demo_math_spec.rb
```
Expected: 1 example, 0 failures.
3. Remove the file once done (to keep repo clean):
```bash
rm spec/demo_math_spec.rb
```

### Test data and MongoDB

- Specs create and persist documents via Mongoid (e.g., `Block`, `Blockchain`). Use a dedicated `MONGO_DB_NAME` for tests to avoid polluting dev data.
- No cleaning strategy is configured. If isolation becomes necessary, consider adding `database_cleaner-mongoid` or dropping the test DB between runs.

## Additional Development Notes

### API behavior

- `main.rb` sets `content_type :json` for POST requests in a `before` block. If API specs expect more strict headers (e.g., `application/json` vs `text/html`), ensure routes are executed in the same Rack env as tests (Sinatra + rack-test). If content-type mismatches persist, review middleware or how tests mount the app.

### Code style and linting

- RuboCop with `rubocop-rspec` is configured in `.rubocop.yml`.
- Target Ruby: 3.2
- Selected Metrics/Style cops are tuned; specs and config directories are largely excluded from method/ block length checks.
- Run lint:
```
2) Run it:
```bash
ENVIRONMENT=test MONGO_DB_NAME=chain_forge_test MONGO_DB_HOST=127.0.0.1 MONGO_DB_PORT=27017 \
bundle exec rspec spec/demo_math_spec.rb
```
Expected: 1 example, 0 failures (observed).
3) Remove the file when done:
```bash
rm spec/demo_math_spec.rb
```

- Coverage:
```bash
bundle exec rubocop
COVERAGE=true ENVIRONMENT=test MONGO_DB_NAME=chain_forge_test MONGO_DB_HOST=127.0.0.1 MONGO_DB_PORT=27017 \
bundle exec rspec
# Report: coverage/index.html
```
- `spec/spec_helper.rb` preloads SimpleCov when `COVERAGE` is set and applies filters/groups; minimum coverage is set to 80%.

### Project structure

- Core domain:
- `src/block.rb` — `Block` model with SHA256 hashing and `valid_data?` verification.
- `src/blockchain.rb` — `Blockchain` aggregate with `add_genesis_block`, `add_block`, `integrity_valid?`.
- App entrypoint: `main.rb` (Sinatra routes for creating chains, adding blocks, validating block data).
- Tests: `spec/` directory with unit specs for `Block` and `Blockchain`, and API specs.
- Test data & MongoDB:
- Specs persist via Mongoid; use a dedicated test DB (`MONGO_DB_NAME=chain_forge_test`).
- No cleaning strategy is configured. For isolation across runs, consider dropping the test DB between runs or adding `database_cleaner-mongoid`.

### Debugging tips

- Use focused RSpec runs (`-e`, `:line_number`).
- Inspect Mongo documents in a console by starting `irb` with the same environment:
- Running tests inside container (optional):
```bash
ENVIRONMENT=development MONGO_DB_NAME=chain_forge_dev MONGO_DB_HOST=127.0.0.1 MONGO_DB_PORT=27017 \
bundle exec irb -r ./src/blockchain -r ./src/block
docker-compose exec app bash
# inside container
ENVIRONMENT=test MONGO_DB_NAME=chain_forge_test MONGO_DB_HOST=db MONGO_DB_PORT=27017 bundle exec rspec
```
- When debugging hashing/time-sensitive assertions, compare against `created_at.to_i` (used in hash calculation).

### Docker notes

- The provided `docker-compose.yml` spins up `app` and `db`. The `app` container runs `ruby main.rb -p 1910` per `Dockerfile` CMD. For test runs, it’s simpler to run RSpec on the host and use the `db` service for Mongo.
- If you want to run tests inside the container, `docker-compose exec app bash` then run the same `ENVIRONMENT=test` commands with `MONGO_DB_HOST=db`.

---

This document reflects commands verified on 2025-11-08 23:58 local time. Keep it updated as the test suite and APIs evolve.
### Code & Project Notes

- Structure:
- `src/block.rb` — `Block` model with SHA256 hashing, PoW attributes (`nonce`, `difficulty`), and `valid_data?`.
- `src/blockchain.rb` — Chain aggregate; `add_genesis_block`, `add_block`, `last_block`, `integrity_valid?`.
- `main.rb` — Sinatra app; routes:
- `GET /` — hello text (HTML content-type).
- `POST /api/v1/chain` — creates a chain.
- `POST /api/v1/chain/:id/block` — validates payload via `BlockDataContract` and mines a block.
- `POST /api/v1/chain/:id/block/:block_id/valid` — validates provided data against stored block.
- `GET /api/v1/chain/:id/block/:block_id` — returns block details including `valid_hash` and mining metadata.
- `src/validators.rb` — Dry-validation contracts (e.g., `BlockDataContract`).
- `config/mongoid.yml` — uses only `MONGO_DB_*` envs; no auth block.
- `config/rack_attack.rb` — Rack::Attack throttling; disabled when `ENVIRONMENT=test`.

- API behavior specifics:
- `before` in app namespace sets `content_type :json` for API routes; POSTs also get JSON via global `before`. If rack/test expectations change, ensure tests mount `Sinatra::Application` and set `CONTENT_TYPE` for JSON posts (as in specs).

- Linting:
```bash
bundle exec rubocop
```
- Target Ruby: 3.2; spec/config dirs are relaxed on Metrics.

- Debugging tips:
- Time-sensitive assertions use `created_at.to_i` in hashing; compare against integer timestamps to avoid flakiness.
- Quick IRB with models loaded:
```bash
ENVIRONMENT=development MONGO_DB_NAME=chain_forge_dev MONGO_DB_HOST=127.0.0.1 MONGO_DB_PORT=27017 \
bundle exec irb -r ./src/blockchain -r ./src/block
```

- Troubleshooting:
- Connection refused on Mongo: ensure `docker-compose up -d` is running or that `MONGO_DB_HOST/PORT` are correct.
- Content-Type mismatches in API tests: check the global/namespace `content_type :json` and `CONTENT_TYPE` header in requests.
- Rack::Attack blocks: ensure `ENVIRONMENT=test` for specs; middleware disabled in that env.
2 changes: 1 addition & 1 deletion main.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

chain_id = params[:id]
blockchain = find_block_chain(chain_id)
difficulty = validation[:difficulty] || 2
difficulty = validation[:difficulty] || ENV.fetch('DEFAULT_DIFFICULTY', '2').to_i
block = blockchain.add_block(validation[:data], difficulty: difficulty)

{
Expand Down
2 changes: 1 addition & 1 deletion src/block.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Block
field :previous_hash, type: String
field :_hash, type: String, as: :hash
field :nonce, type: Integer, default: 0
field :difficulty, type: Integer, default: 2
field :difficulty, type: Integer, default: -> { ENV.fetch('DEFAULT_DIFFICULTY', '2').to_i }

belongs_to :blockchain

Expand Down