Skip to content

Feat: fixed session new endpoints#1173

Open
hanka wants to merge 26 commits intomasterfrom
feat/AirBeamMini2-fixed-session
Open

Feat: fixed session new endpoints#1173
hanka wants to merge 26 commits intomasterfrom
feat/AirBeamMini2-fixed-session

Conversation

@hanka
Copy link
Copy Markdown
Collaborator

@hanka hanka commented Mar 30, 2026

2 new API endpoints to support new AirBeam software:

  • create fixed sessions with streams, returns sensor type ids for the new way of sending measurements by AirBeam
  • create measurements for fixed sessions by sending binary data

hanka added 7 commits March 30, 2026 15:43
…rement_type_id on streams

Introduces three migrations for the AirBeamMini2 endpoint integration:
- `devices` table (mac_address, model, optional name) with unique index on mac_address
- `device_id` foreign key on `sessions` (nullable) to link sessions to the sending device
- `measurement_type_id` integer on `streams` with a partial unique index per session,
  enabling compact numeric stream identification in the AirBeamMini2 binary protocol
- Add Device model (mac_address, model, optional name) with presence/uniqueness validations
- Add optional device association to Session (belongs_to :device, optional: true)
- Add AirBeamMini2 entries to Sensor::CANONICAL_SENSOR_NAME_MAP
- Add five new Sensor constants for canonical stream metadata:
  CANONICAL_MEASUREMENT_TYPE_IDS, CANONICAL_UNIT_SYMBOLS, CANONICAL_MEASUREMENT_TYPES,
  CANONICAL_UNIT_NAMES, CANONICAL_MEASUREMENT_SHORT_TYPES
- Seed AirBeam Source record (idempotent find_or_create_by!)
- Add Device factory, device and sensor model specs
…session creation

Adds the first of two new AirBeamMini2 endpoints that replace the legacy realtime session flow:

- Contract (Dry::Validation): validates uuid, title, lat/lng, airbeam info, and streams array
- Creator service: resolves timezone from coordinates, creates Device (find-or-create), creates
  FixedSession with legacy Stream records and assigns measurement_type_id per stream ordinal
- Controller with token + Devise auth; renders {location, streams} JSON including measurement_type_id
- Nested routes under namespace :v3

The mobile app calls this endpoint to register a new session before configuring the AirBeam.
The response's measurement_type_id values are passed to the AirBeam to identify stream types
in the subsequent binary measurement uploads.
…ingestion endpoint

Adds the AirBeamMini2 binary measurement upload endpoint:

Binary format (little-endian):
  [4B] magic "ABBA" | [2B] uint16 count | N×[4B uint32 epoch + 1B type_id + 4B float32 value] | [1B] XOR checksum

- BinaryParser: validates magic, measurement count, payload size, and XOR checksum;
  returns parsed array of {epoch, measurement_type_id, value} hashes
- Ingester: resolves streams by measurement_type_id, converts UTC epoch to local wall-clock
  time (compatible with legacy daily-averages SQL), bulk-upserts FixedMeasurements with
  on_duplicate_key_update for resync support, updates session timestamps,
  optionally triggers daily/hourly averages recalculation on sync uploads
- Controller reads raw request body (application/octet-stream), delegates to Ingester
Adds a reference table of all API endpoints used by iOS and Android mobile apps,
covering fixed session management, mobile session upload, sync, threshold alerts,
and account management. Replaces the outdated endpoint list previously only in doc/api.md.
Big-endian is preferred for public network protocols (network byte order).
Update unpack strings in BinaryParser (a4v→a4n for header, VCe→NCg per measurement)
and all test build_binary helpers to match.
- Add rswag-api, rswag-ui (always loaded) and rswag-specs (test group) to Gemfile
- Mount Rswag::Api::Engine at /api-docs (serves swagger.yaml in all envs)
- Mount Rswag::Ui::Engine at /api-docs only in non-production (interactive UI)
- Add swagger_helper.rb and spec/swagger/v3/fixed_sessions_spec.rb documenting
  both AirBeamMini2 endpoints including the binary format description
- Commit generated swagger/v3/swagger.yaml (regenerate with:
  RAILS_ENV=test PATTERN="spec/swagger/**/*_spec.rb" bundle exec rake rswag:specs:swaggerize)
@hanka hanka force-pushed the feat/AirBeamMini2-fixed-session branch from 3f374c1 to f3b64a2 Compare March 31, 2026 11:47
hanka added 6 commits April 1, 2026 13:22
Split the index creation out of the add_device_id migration into a
dedicated migration with disable_ddl_transaction! + algorithm: :concurrently.

On a large sessions table, a non-concurrent index build holds a ShareLock
(blocking writes) for the full duration of the table scan. The concurrent
build avoids this — it runs in the background without blocking reads or writes,
at the cost of two table scans instead of one.

The column add and FK constraint remain in the original migration (both are
safe: ADD COLUMN is instant for nullable columns in PG 11+, and ADD FOREIGN KEY
skips validation for existing NULL values).
Replaced run_test! with skip examples. The SwaggerFormatter processes
example-group metadata (not individual examples), so YAML generation via
the rake task is unaffected. Direct 'rspec spec/swagger/' runs now report
7 pending instead of 7 failures.
…ntract

Follows the pattern of Api::MobileSessionsContract and Api::FixedSessionsContract:
contract validation happens at the controller level, and the service receives
pre-validated data. Naming convention: verb-prefix (Create) distinguishes it
from the existing query contract Api::FixedSessionsContract (GET params).

- Add app/models/api/create_fixed_session_contract.rb
- Update controller to call contract before invoking Creator
- Remove internal contract call from Creator (no longer its responsibility)
- Delete AirBeamMini2::FixedSessions::Contract and its spec
- Add spec/models/api/create_fixed_session_contract_spec.rb
- FixedSessions::Creator — shared session creation, no device-specific logic
- FixedSessions::AirBeamMini2::BinaryParser — binary protocol parsing (Mini2-specific)
- FixedSessions::AirBeamMini2::Ingester — binary measurement ingestion (Mini2-specific)

The FixedSessions top-level namespace will grow to serve all AirBeam models
using the new v3 endpoint. The AirBeamMini2 sub-namespace scopes the binary
protocol services without polluting the shared layer.

Use ::FixedSessions in controllers to avoid constant lookup collision with
the Api::V3::FixedSessions controller namespace.
@hanka hanka force-pushed the feat/AirBeamMini2-fixed-session branch from d91322b to abcb13e Compare April 1, 2026 11:22
@hanka hanka changed the title Feat: AirBeamMini2 fixed session new endpoints Feat: fixed session new endpoints Apr 7, 2026
@hanka hanka marked this pull request as ready for review April 8, 2026 09:58
@hanka hanka self-assigned this Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant