From 97c3ae6552cef28cf6daf6862efdbad5af010531 Mon Sep 17 00:00:00 2001 From: Auston Bunsen Date: Fri, 3 Oct 2025 12:14:45 -0400 Subject: [PATCH] First pass at models, still missing some core models and associations --- Gemfile | 1 + Gemfile.lock | 9 + app/models/access_controller.rb | 3 + app/models/access_path.rb | 2 + app/models/access_rule_set.rb | 2 + app/models/building.rb | 2 + app/models/credential.rb | 4 + app/models/credential_format.rb | 2 + app/models/credential_format_field.rb | 2 + app/models/credential_format_field_bit.rb | 3 + app/models/credential_format_parity_bit.rb | 2 + .../credential_format_parity_bit_range.rb | 3 + app/models/credential_type.rb | 2 + app/models/entry_way.rb | 4 + app/models/group.rb | 2 + app/models/person.rb | 3 + app/models/reader.rb | 4 + app/models/sector.rb | 4 + app/models/sensor.rb | 4 + db/migrate/20251002155507_create_buildings.rb | 15 ++ db/migrate/20251002155745_create_sectors.rb | 11 ++ .../20251002160131_create_access_paths.rb | 9 + ...0251002160746_create_access_controllers.rb | 15 ++ .../20251002160910_create_entry_ways.rb | 11 ++ db/migrate/20251002161415_create_readers.rb | 16 ++ db/migrate/20251002161515_create_groups.rb | 9 + db/migrate/20251002161628_create_people.rb | 15 ++ db/migrate/20251002161732_create_sensors.rb | 16 ++ ...0251002162628_create_credential_formats.rb | 10 + ...2162752_create_credential_format_fields.rb | 9 + ...403_create_credential_format_field_bits.rb | 11 ++ ...01_create_credential_format_parity_bits.rb | 10 + ...ate_credential_format_parity_bit_ranges.rb | 11 ++ .../20251002164322_create_credential_types.rb | 11 ++ .../20251002165720_create_credentials.rb | 10 + .../20251003152945_create_access_rule_sets.rb | 9 + db/schema.rb | 183 ++++++++++++++++++ erd.pdf | Bin 0 -> 41393 bytes test/fixtures/access_controllers.yml | 19 ++ test/fixtures/access_paths.yml | 7 + test/fixtures/access_rule_sets.yml | 7 + test/fixtures/buildings.yml | 19 ++ .../fixtures/credential_format_field_bits.yml | 11 ++ test/fixtures/credential_format_fields.yml | 7 + .../credential_format_parity_bit_ranges.yml | 11 ++ .../credential_format_parity_bits.yml | 9 + test/fixtures/credential_formats.yml | 9 + test/fixtures/credential_types.yml | 11 ++ test/fixtures/credentials.yml | 9 + test/fixtures/entry_ways.yml | 11 ++ test/fixtures/groups.yml | 7 + test/fixtures/people.yml | 19 ++ test/fixtures/readers.yml | 21 ++ test/fixtures/sectors.yml | 11 ++ test/fixtures/sensors.yml | 21 ++ test/models/access_controller_test.rb | 7 + test/models/access_path_test.rb | 7 + test/models/access_rule_set_test.rb | 7 + test/models/building_test.rb | 7 + .../credential_format_field_bit_test.rb | 7 + test/models/credential_format_field_test.rb | 7 + ...credential_format_parity_bit_range_test.rb | 7 + .../credential_format_parity_bit_test.rb | 7 + test/models/credential_format_test.rb | 7 + test/models/credential_test.rb | 7 + test/models/credential_type_test.rb | 7 + test/models/entry_way_test.rb | 7 + test/models/group_test.rb | 7 + test/models/person_test.rb | 7 + test/models/reader_test.rb | 7 + test/models/sector_test.rb | 7 + test/models/sensor_test.rb | 7 + 72 files changed, 767 insertions(+) create mode 100644 app/models/access_controller.rb create mode 100644 app/models/access_path.rb create mode 100644 app/models/access_rule_set.rb create mode 100644 app/models/building.rb create mode 100644 app/models/credential.rb create mode 100644 app/models/credential_format.rb create mode 100644 app/models/credential_format_field.rb create mode 100644 app/models/credential_format_field_bit.rb create mode 100644 app/models/credential_format_parity_bit.rb create mode 100644 app/models/credential_format_parity_bit_range.rb create mode 100644 app/models/credential_type.rb create mode 100644 app/models/entry_way.rb create mode 100644 app/models/group.rb create mode 100644 app/models/person.rb create mode 100644 app/models/reader.rb create mode 100644 app/models/sector.rb create mode 100644 app/models/sensor.rb create mode 100644 db/migrate/20251002155507_create_buildings.rb create mode 100644 db/migrate/20251002155745_create_sectors.rb create mode 100644 db/migrate/20251002160131_create_access_paths.rb create mode 100644 db/migrate/20251002160746_create_access_controllers.rb create mode 100644 db/migrate/20251002160910_create_entry_ways.rb create mode 100644 db/migrate/20251002161415_create_readers.rb create mode 100644 db/migrate/20251002161515_create_groups.rb create mode 100644 db/migrate/20251002161628_create_people.rb create mode 100644 db/migrate/20251002161732_create_sensors.rb create mode 100644 db/migrate/20251002162628_create_credential_formats.rb create mode 100644 db/migrate/20251002162752_create_credential_format_fields.rb create mode 100644 db/migrate/20251002163403_create_credential_format_field_bits.rb create mode 100644 db/migrate/20251002163501_create_credential_format_parity_bits.rb create mode 100644 db/migrate/20251002163557_create_credential_format_parity_bit_ranges.rb create mode 100644 db/migrate/20251002164322_create_credential_types.rb create mode 100644 db/migrate/20251002165720_create_credentials.rb create mode 100644 db/migrate/20251003152945_create_access_rule_sets.rb create mode 100644 db/schema.rb create mode 100644 erd.pdf create mode 100644 test/fixtures/access_controllers.yml create mode 100644 test/fixtures/access_paths.yml create mode 100644 test/fixtures/access_rule_sets.yml create mode 100644 test/fixtures/buildings.yml create mode 100644 test/fixtures/credential_format_field_bits.yml create mode 100644 test/fixtures/credential_format_fields.yml create mode 100644 test/fixtures/credential_format_parity_bit_ranges.yml create mode 100644 test/fixtures/credential_format_parity_bits.yml create mode 100644 test/fixtures/credential_formats.yml create mode 100644 test/fixtures/credential_types.yml create mode 100644 test/fixtures/credentials.yml create mode 100644 test/fixtures/entry_ways.yml create mode 100644 test/fixtures/groups.yml create mode 100644 test/fixtures/people.yml create mode 100644 test/fixtures/readers.yml create mode 100644 test/fixtures/sectors.yml create mode 100644 test/fixtures/sensors.yml create mode 100644 test/models/access_controller_test.rb create mode 100644 test/models/access_path_test.rb create mode 100644 test/models/access_rule_set_test.rb create mode 100644 test/models/building_test.rb create mode 100644 test/models/credential_format_field_bit_test.rb create mode 100644 test/models/credential_format_field_test.rb create mode 100644 test/models/credential_format_parity_bit_range_test.rb create mode 100644 test/models/credential_format_parity_bit_test.rb create mode 100644 test/models/credential_format_test.rb create mode 100644 test/models/credential_test.rb create mode 100644 test/models/credential_type_test.rb create mode 100644 test/models/entry_way_test.rb create mode 100644 test/models/group_test.rb create mode 100644 test/models/person_test.rb create mode 100644 test/models/reader_test.rb create mode 100644 test/models/sector_test.rb create mode 100644 test/models/sensor_test.rb diff --git a/Gemfile b/Gemfile index a62907b..186b377 100644 --- a/Gemfile +++ b/Gemfile @@ -54,6 +54,7 @@ end group :development do # Use console on exceptions pages [https://github.com/rails/web-console] gem "web-console" + gem "rails-erd" end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index e8f3f8f..1f6ed98 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,6 +96,7 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) + choice (0.2.0) concurrent-ruby (1.3.5) connection_pool (2.5.4) crass (1.0.6) @@ -235,6 +236,11 @@ GEM activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) + rails-erd (1.7.2) + activerecord (>= 4.2) + activesupport (>= 4.2) + choice (~> 0.2.0) + ruby-graphviz (~> 1.2) rails-html-sanitizer (1.6.2) loofah (~> 2.21) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) @@ -284,6 +290,8 @@ GEM rubocop (>= 1.72) rubocop-performance (>= 1.24) rubocop-rails (>= 2.30) + ruby-graphviz (1.2.5) + rexml ruby-progressbar (1.13.0) rubyzip (3.1.1) securerandom (0.4.1) @@ -384,6 +392,7 @@ DEPENDENCIES propshaft puma (>= 5.0) rails (~> 8.0.3) + rails-erd rubocop-rails-omakase selenium-webdriver solid_cable diff --git a/app/models/access_controller.rb b/app/models/access_controller.rb new file mode 100644 index 0000000..ec725f8 --- /dev/null +++ b/app/models/access_controller.rb @@ -0,0 +1,3 @@ +class AccessController < ApplicationRecord + belongs_to :sector +end diff --git a/app/models/access_path.rb b/app/models/access_path.rb new file mode 100644 index 0000000..ef5dee8 --- /dev/null +++ b/app/models/access_path.rb @@ -0,0 +1,2 @@ +class AccessPath < ApplicationRecord +end diff --git a/app/models/access_rule_set.rb b/app/models/access_rule_set.rb new file mode 100644 index 0000000..4298db5 --- /dev/null +++ b/app/models/access_rule_set.rb @@ -0,0 +1,2 @@ +class AccessRuleSet < ApplicationRecord +end diff --git a/app/models/building.rb b/app/models/building.rb new file mode 100644 index 0000000..f1959a2 --- /dev/null +++ b/app/models/building.rb @@ -0,0 +1,2 @@ +class Building < ApplicationRecord +end diff --git a/app/models/credential.rb b/app/models/credential.rb new file mode 100644 index 0000000..a8d612d --- /dev/null +++ b/app/models/credential.rb @@ -0,0 +1,4 @@ +class Credential < ApplicationRecord + belongs_to :person + belongs_to :credential_type +end diff --git a/app/models/credential_format.rb b/app/models/credential_format.rb new file mode 100644 index 0000000..f50b74d --- /dev/null +++ b/app/models/credential_format.rb @@ -0,0 +1,2 @@ +class CredentialFormat < ApplicationRecord +end diff --git a/app/models/credential_format_field.rb b/app/models/credential_format_field.rb new file mode 100644 index 0000000..b387ade --- /dev/null +++ b/app/models/credential_format_field.rb @@ -0,0 +1,2 @@ +class CredentialFormatField < ApplicationRecord +end diff --git a/app/models/credential_format_field_bit.rb b/app/models/credential_format_field_bit.rb new file mode 100644 index 0000000..db910a6 --- /dev/null +++ b/app/models/credential_format_field_bit.rb @@ -0,0 +1,3 @@ +class CredentialFormatFieldBit < ApplicationRecord + belongs_to :credential_format_field +end diff --git a/app/models/credential_format_parity_bit.rb b/app/models/credential_format_parity_bit.rb new file mode 100644 index 0000000..64ab11f --- /dev/null +++ b/app/models/credential_format_parity_bit.rb @@ -0,0 +1,2 @@ +class CredentialFormatParityBit < ApplicationRecord +end diff --git a/app/models/credential_format_parity_bit_range.rb b/app/models/credential_format_parity_bit_range.rb new file mode 100644 index 0000000..9b677d4 --- /dev/null +++ b/app/models/credential_format_parity_bit_range.rb @@ -0,0 +1,3 @@ +class CredentialFormatParityBitRange < ApplicationRecord + belongs_to :credential_format_parity +end diff --git a/app/models/credential_type.rb b/app/models/credential_type.rb new file mode 100644 index 0000000..95d2ca9 --- /dev/null +++ b/app/models/credential_type.rb @@ -0,0 +1,2 @@ +class CredentialType < ApplicationRecord +end diff --git a/app/models/entry_way.rb b/app/models/entry_way.rb new file mode 100644 index 0000000..2c26465 --- /dev/null +++ b/app/models/entry_way.rb @@ -0,0 +1,4 @@ +class EntryWay < ApplicationRecord + belongs_to :sector + belongs_to :access_controller +end diff --git a/app/models/group.rb b/app/models/group.rb new file mode 100644 index 0000000..a8e77b5 --- /dev/null +++ b/app/models/group.rb @@ -0,0 +1,2 @@ +class Group < ApplicationRecord +end diff --git a/app/models/person.rb b/app/models/person.rb new file mode 100644 index 0000000..853c6cd --- /dev/null +++ b/app/models/person.rb @@ -0,0 +1,3 @@ +class Person < ApplicationRecord + belongs_to :group +end diff --git a/app/models/reader.rb b/app/models/reader.rb new file mode 100644 index 0000000..24cf8d6 --- /dev/null +++ b/app/models/reader.rb @@ -0,0 +1,4 @@ +class Reader < ApplicationRecord + belongs_to :access_controller + belongs_to :entry_way +end diff --git a/app/models/sector.rb b/app/models/sector.rb new file mode 100644 index 0000000..109ca43 --- /dev/null +++ b/app/models/sector.rb @@ -0,0 +1,4 @@ +class Sector < ApplicationRecord + belongs_to :building + belongs_to :parent +end diff --git a/app/models/sensor.rb b/app/models/sensor.rb new file mode 100644 index 0000000..c982027 --- /dev/null +++ b/app/models/sensor.rb @@ -0,0 +1,4 @@ +class Sensor < ApplicationRecord + belongs_to :access_controller + belongs_to :entry_way +end diff --git a/db/migrate/20251002155507_create_buildings.rb b/db/migrate/20251002155507_create_buildings.rb new file mode 100644 index 0000000..9e205cd --- /dev/null +++ b/db/migrate/20251002155507_create_buildings.rb @@ -0,0 +1,15 @@ +class CreateBuildings < ActiveRecord::Migration[8.0] + def change + create_table :buildings do |t| + t.string :name + t.string :address + t.string :address_2 + t.string :city + t.string :region + t.string :country + t.string :postal_code + + t.timestamps + end + end +end diff --git a/db/migrate/20251002155745_create_sectors.rb b/db/migrate/20251002155745_create_sectors.rb new file mode 100644 index 0000000..be4c150 --- /dev/null +++ b/db/migrate/20251002155745_create_sectors.rb @@ -0,0 +1,11 @@ +class CreateSectors < ActiveRecord::Migration[8.0] + def change + create_table :sectors do |t| + t.string :name + t.references :building, null: false, foreign_key: true + t.references :parent, null: true, foreign_key: { to_table: :sectors } + + t.timestamps + end + end +end diff --git a/db/migrate/20251002160131_create_access_paths.rb b/db/migrate/20251002160131_create_access_paths.rb new file mode 100644 index 0000000..c74f95a --- /dev/null +++ b/db/migrate/20251002160131_create_access_paths.rb @@ -0,0 +1,9 @@ +class CreateAccessPaths < ActiveRecord::Migration[8.0] + def change + create_table :access_paths do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20251002160746_create_access_controllers.rb b/db/migrate/20251002160746_create_access_controllers.rb new file mode 100644 index 0000000..bff8d3a --- /dev/null +++ b/db/migrate/20251002160746_create_access_controllers.rb @@ -0,0 +1,15 @@ +class CreateAccessControllers < ActiveRecord::Migration[8.0] + def change + create_table :access_controllers do |t| + t.string :name + t.string :model + t.string :brand + t.json :metadata + t.json :public_metadata + t.references :sector, null: false, foreign_key: true + t.boolean :is_virtual + + t.timestamps + end + end +end diff --git a/db/migrate/20251002160910_create_entry_ways.rb b/db/migrate/20251002160910_create_entry_ways.rb new file mode 100644 index 0000000..bc4a13b --- /dev/null +++ b/db/migrate/20251002160910_create_entry_ways.rb @@ -0,0 +1,11 @@ +class CreateEntryWays < ActiveRecord::Migration[8.0] + def change + create_table :entry_ways do |t| + t.string :name + t.references :sector, null: false, foreign_key: true + t.references :access_controller, null: false, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20251002161415_create_readers.rb b/db/migrate/20251002161415_create_readers.rb new file mode 100644 index 0000000..8400f43 --- /dev/null +++ b/db/migrate/20251002161415_create_readers.rb @@ -0,0 +1,16 @@ +class CreateReaders < ActiveRecord::Migration[8.0] + def change + create_table :readers do |t| + t.string :name + t.string :brand + t.string :model + t.string :serial_number + t.references :access_controller, null: false, foreign_key: true + t.string :last_known_state + t.datetime :last_state_update + t.references :entry_way, null: false, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20251002161515_create_groups.rb b/db/migrate/20251002161515_create_groups.rb new file mode 100644 index 0000000..66e9c8e --- /dev/null +++ b/db/migrate/20251002161515_create_groups.rb @@ -0,0 +1,9 @@ +class CreateGroups < ActiveRecord::Migration[8.0] + def change + create_table :groups do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20251002161628_create_people.rb b/db/migrate/20251002161628_create_people.rb new file mode 100644 index 0000000..dec8ab8 --- /dev/null +++ b/db/migrate/20251002161628_create_people.rb @@ -0,0 +1,15 @@ +class CreatePeople < ActiveRecord::Migration[8.0] + def change + create_table :people do |t| + t.string :first_name + t.string :last_name + t.string :title + t.string :phone_number + t.string :email + t.references :group, null: false, foreign_key: true + t.json :metadata + + t.timestamps + end + end +end diff --git a/db/migrate/20251002161732_create_sensors.rb b/db/migrate/20251002161732_create_sensors.rb new file mode 100644 index 0000000..c1caf91 --- /dev/null +++ b/db/migrate/20251002161732_create_sensors.rb @@ -0,0 +1,16 @@ +class CreateSensors < ActiveRecord::Migration[8.0] + def change + create_table :sensors do |t| + t.string :name + t.string :brand + t.string :model + t.string :serial_number + t.references :access_controller, null: false, foreign_key: true + t.references :entry_way, null: false, foreign_key: true + t.string :last_known_state + t.datetime :last_state_update + + t.timestamps + end + end +end diff --git a/db/migrate/20251002162628_create_credential_formats.rb b/db/migrate/20251002162628_create_credential_formats.rb new file mode 100644 index 0000000..791f923 --- /dev/null +++ b/db/migrate/20251002162628_create_credential_formats.rb @@ -0,0 +1,10 @@ +class CreateCredentialFormats < ActiveRecord::Migration[8.0] + def change + create_table :credential_formats do |t| + t.string :name + t.integer :length + + t.timestamps + end + end +end diff --git a/db/migrate/20251002162752_create_credential_format_fields.rb b/db/migrate/20251002162752_create_credential_format_fields.rb new file mode 100644 index 0000000..79433e6 --- /dev/null +++ b/db/migrate/20251002162752_create_credential_format_fields.rb @@ -0,0 +1,9 @@ +class CreateCredentialFormatFields < ActiveRecord::Migration[8.0] + def change + create_table :credential_format_fields do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20251002163403_create_credential_format_field_bits.rb b/db/migrate/20251002163403_create_credential_format_field_bits.rb new file mode 100644 index 0000000..0d3a02b --- /dev/null +++ b/db/migrate/20251002163403_create_credential_format_field_bits.rb @@ -0,0 +1,11 @@ +class CreateCredentialFormatFieldBits < ActiveRecord::Migration[8.0] + def change + create_table :credential_format_field_bits do |t| + t.integer :index + t.references :credential_format_field, null: false, foreign_key: true + t.integer :position + + t.timestamps + end + end +end diff --git a/db/migrate/20251002163501_create_credential_format_parity_bits.rb b/db/migrate/20251002163501_create_credential_format_parity_bits.rb new file mode 100644 index 0000000..79fbda6 --- /dev/null +++ b/db/migrate/20251002163501_create_credential_format_parity_bits.rb @@ -0,0 +1,10 @@ +class CreateCredentialFormatParityBits < ActiveRecord::Migration[8.0] + def change + create_table :credential_format_parity_bits do |t| + t.string :kind + t.string :index + + t.timestamps + end + end +end diff --git a/db/migrate/20251002163557_create_credential_format_parity_bit_ranges.rb b/db/migrate/20251002163557_create_credential_format_parity_bit_ranges.rb new file mode 100644 index 0000000..c5e17b4 --- /dev/null +++ b/db/migrate/20251002163557_create_credential_format_parity_bit_ranges.rb @@ -0,0 +1,11 @@ +class CreateCredentialFormatParityBitRanges < ActiveRecord::Migration[8.0] + def change + create_table :credential_format_parity_bit_ranges do |t| + t.references :credential_format_parity, null: false, foreign_key: true + t.integer :index + t.integer :position + + t.timestamps + end + end +end diff --git a/db/migrate/20251002164322_create_credential_types.rb b/db/migrate/20251002164322_create_credential_types.rb new file mode 100644 index 0000000..8636dda --- /dev/null +++ b/db/migrate/20251002164322_create_credential_types.rb @@ -0,0 +1,11 @@ +class CreateCredentialTypes < ActiveRecord::Migration[8.0] + def change + create_table :credential_types do |t| + t.string :kind + t.string :frequency + t.string :protocol + + t.timestamps + end + end +end diff --git a/db/migrate/20251002165720_create_credentials.rb b/db/migrate/20251002165720_create_credentials.rb new file mode 100644 index 0000000..4ab7d27 --- /dev/null +++ b/db/migrate/20251002165720_create_credentials.rb @@ -0,0 +1,10 @@ +class CreateCredentials < ActiveRecord::Migration[8.0] + def change + create_table :credentials do |t| + t.references :person, null: false, foreign_key: true + t.references :credential_type, null: false, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20251003152945_create_access_rule_sets.rb b/db/migrate/20251003152945_create_access_rule_sets.rb new file mode 100644 index 0000000..077c836 --- /dev/null +++ b/db/migrate/20251003152945_create_access_rule_sets.rb @@ -0,0 +1,9 @@ +class CreateAccessRuleSets < ActiveRecord::Migration[8.0] + def change + create_table :access_rule_sets do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..4acacc6 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,183 @@ +# 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.0].define(version: 2025_10_02_165720) do + create_table "access_controllers", force: :cascade do |t| + t.string "name" + t.string "model" + t.string "brand" + t.json "metadata" + t.json "public_metadata" + t.integer "sector_id", null: false + t.boolean "is_virtual" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["sector_id"], name: "index_access_controllers_on_sector_id" + end + + create_table "access_paths", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "buildings", force: :cascade do |t| + t.string "name" + t.string "address" + t.string "address_2" + t.string "city" + t.string "region" + t.string "country" + t.string "postal_code" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "credential_format_field_bits", force: :cascade do |t| + t.integer "index" + t.integer "credential_format_field_id", null: false + t.integer "position" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["credential_format_field_id"], name: "idx_on_credential_format_field_id_fb5865f3a1" + end + + create_table "credential_format_fields", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "credential_format_parity_bit_ranges", force: :cascade do |t| + t.integer "credential_format_parity_id", null: false + t.integer "index" + t.integer "position" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["credential_format_parity_id"], name: "idx_on_credential_format_parity_id_aed47f38e7" + end + + create_table "credential_format_parity_bits", force: :cascade do |t| + t.string "kind" + t.string "index" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "credential_formats", force: :cascade do |t| + t.string "name" + t.integer "length" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "credential_types", force: :cascade do |t| + t.string "kind" + t.string "frequency" + t.string "protocol" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "credentials", force: :cascade do |t| + t.integer "person_id", null: false + t.integer "credential_type_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["credential_type_id"], name: "index_credentials_on_credential_type_id" + t.index ["person_id"], name: "index_credentials_on_person_id" + end + + create_table "entry_ways", force: :cascade do |t| + t.string "name" + t.integer "sector_id", null: false + t.integer "access_controller_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["access_controller_id"], name: "index_entry_ways_on_access_controller_id" + t.index ["sector_id"], name: "index_entry_ways_on_sector_id" + end + + create_table "groups", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "people", force: :cascade do |t| + t.string "first_name" + t.string "last_name" + t.string "title" + t.string "phone_number" + t.string "email" + t.integer "group_id", null: false + t.json "metadata" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["group_id"], name: "index_people_on_group_id" + end + + create_table "readers", force: :cascade do |t| + t.string "name" + t.string "brand" + t.string "model" + t.string "serial_number" + t.integer "access_controller_id", null: false + t.string "last_known_state" + t.datetime "last_state_update" + t.integer "entry_way_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["access_controller_id"], name: "index_readers_on_access_controller_id" + t.index ["entry_way_id"], name: "index_readers_on_entry_way_id" + end + + create_table "sectors", force: :cascade do |t| + t.string "name" + t.integer "building_id", null: false + t.integer "parent_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["building_id"], name: "index_sectors_on_building_id" + t.index ["parent_id"], name: "index_sectors_on_parent_id" + end + + create_table "sensors", force: :cascade do |t| + t.string "name" + t.string "brand" + t.string "model" + t.string "serial_number" + t.integer "access_controller_id", null: false + t.integer "entry_way_id", null: false + t.string "last_known_state" + t.datetime "last_state_update" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["access_controller_id"], name: "index_sensors_on_access_controller_id" + t.index ["entry_way_id"], name: "index_sensors_on_entry_way_id" + end + + add_foreign_key "access_controllers", "sectors" + add_foreign_key "credential_format_field_bits", "credential_format_fields" + add_foreign_key "credential_format_parity_bit_ranges", "credential_format_parities" + add_foreign_key "credentials", "credential_types" + add_foreign_key "credentials", "people" + add_foreign_key "entry_ways", "access_controllers" + add_foreign_key "entry_ways", "sectors" + add_foreign_key "people", "groups" + add_foreign_key "readers", "access_controllers" + add_foreign_key "readers", "entry_ways" + add_foreign_key "sectors", "buildings" + add_foreign_key "sectors", "sectors", column: "parent_id" + add_foreign_key "sensors", "access_controllers" + add_foreign_key "sensors", "entry_ways" +end diff --git a/erd.pdf b/erd.pdf new file mode 100644 index 0000000000000000000000000000000000000000..520a3a19c2baa03286f251c7850a76f4a8c523d4 GIT binary patch literal 41393 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/access_controllers.yml b/test/fixtures/access_controllers.yml new file mode 100644 index 0000000..4e3b2f4 --- /dev/null +++ b/test/fixtures/access_controllers.yml @@ -0,0 +1,19 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + model: MyString + brand: MyString + metadata: + public_metadata: + sector: one + is_virtual: false + +two: + name: MyString + model: MyString + brand: MyString + metadata: + public_metadata: + sector: two + is_virtual: false diff --git a/test/fixtures/access_paths.yml b/test/fixtures/access_paths.yml new file mode 100644 index 0000000..7d41224 --- /dev/null +++ b/test/fixtures/access_paths.yml @@ -0,0 +1,7 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + +two: + name: MyString diff --git a/test/fixtures/access_rule_sets.yml b/test/fixtures/access_rule_sets.yml new file mode 100644 index 0000000..7d41224 --- /dev/null +++ b/test/fixtures/access_rule_sets.yml @@ -0,0 +1,7 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + +two: + name: MyString diff --git a/test/fixtures/buildings.yml b/test/fixtures/buildings.yml new file mode 100644 index 0000000..426e8c3 --- /dev/null +++ b/test/fixtures/buildings.yml @@ -0,0 +1,19 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + address: MyString + address_2: MyString + city: MyString + region: MyString + country: MyString + postal_code: MyString + +two: + name: MyString + address: MyString + address_2: MyString + city: MyString + region: MyString + country: MyString + postal_code: MyString diff --git a/test/fixtures/credential_format_field_bits.yml b/test/fixtures/credential_format_field_bits.yml new file mode 100644 index 0000000..8060fc8 --- /dev/null +++ b/test/fixtures/credential_format_field_bits.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + index: 1 + credential_format_field: one + position: 1 + +two: + index: 1 + credential_format_field: two + position: 1 diff --git a/test/fixtures/credential_format_fields.yml b/test/fixtures/credential_format_fields.yml new file mode 100644 index 0000000..7d41224 --- /dev/null +++ b/test/fixtures/credential_format_fields.yml @@ -0,0 +1,7 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + +two: + name: MyString diff --git a/test/fixtures/credential_format_parity_bit_ranges.yml b/test/fixtures/credential_format_parity_bit_ranges.yml new file mode 100644 index 0000000..4244a33 --- /dev/null +++ b/test/fixtures/credential_format_parity_bit_ranges.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + credential_format_parity: one + index: 1 + position: 1 + +two: + credential_format_parity: two + index: 1 + position: 1 diff --git a/test/fixtures/credential_format_parity_bits.yml b/test/fixtures/credential_format_parity_bits.yml new file mode 100644 index 0000000..483d6e0 --- /dev/null +++ b/test/fixtures/credential_format_parity_bits.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + kind: MyString + index: MyString + +two: + kind: MyString + index: MyString diff --git a/test/fixtures/credential_formats.yml b/test/fixtures/credential_formats.yml new file mode 100644 index 0000000..a469bf9 --- /dev/null +++ b/test/fixtures/credential_formats.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + length: 1 + +two: + name: MyString + length: 1 diff --git a/test/fixtures/credential_types.yml b/test/fixtures/credential_types.yml new file mode 100644 index 0000000..827ea42 --- /dev/null +++ b/test/fixtures/credential_types.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + kind: MyString + frequency: MyString + protocol: MyString + +two: + kind: MyString + frequency: MyString + protocol: MyString diff --git a/test/fixtures/credentials.yml b/test/fixtures/credentials.yml new file mode 100644 index 0000000..95062e3 --- /dev/null +++ b/test/fixtures/credentials.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + person: one + credential_type: one + +two: + person: two + credential_type: two diff --git a/test/fixtures/entry_ways.yml b/test/fixtures/entry_ways.yml new file mode 100644 index 0000000..8d402ea --- /dev/null +++ b/test/fixtures/entry_ways.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + sector: one + access_controller: one + +two: + name: MyString + sector: two + access_controller: two diff --git a/test/fixtures/groups.yml b/test/fixtures/groups.yml new file mode 100644 index 0000000..7d41224 --- /dev/null +++ b/test/fixtures/groups.yml @@ -0,0 +1,7 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + +two: + name: MyString diff --git a/test/fixtures/people.yml b/test/fixtures/people.yml new file mode 100644 index 0000000..94cad37 --- /dev/null +++ b/test/fixtures/people.yml @@ -0,0 +1,19 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + first_name: MyString + last_name: MyString + title: MyString + phone_number: MyString + email: MyString + group: one + metadata: + +two: + first_name: MyString + last_name: MyString + title: MyString + phone_number: MyString + email: MyString + group: two + metadata: diff --git a/test/fixtures/readers.yml b/test/fixtures/readers.yml new file mode 100644 index 0000000..d1e6065 --- /dev/null +++ b/test/fixtures/readers.yml @@ -0,0 +1,21 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + brand: MyString + model: MyString + serial_number: MyString + access_controller: one + last_known_state: MyString + last_state_update: 2025-10-02 12:14:15 + entry_way: one + +two: + name: MyString + brand: MyString + model: MyString + serial_number: MyString + access_controller: two + last_known_state: MyString + last_state_update: 2025-10-02 12:14:15 + entry_way: two diff --git a/test/fixtures/sectors.yml b/test/fixtures/sectors.yml new file mode 100644 index 0000000..20b91e7 --- /dev/null +++ b/test/fixtures/sectors.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + building: one + parent: one + +two: + name: MyString + building: two + parent: two diff --git a/test/fixtures/sensors.yml b/test/fixtures/sensors.yml new file mode 100644 index 0000000..1cd81fb --- /dev/null +++ b/test/fixtures/sensors.yml @@ -0,0 +1,21 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + brand: MyString + model: MyString + serial_number: MyString + access_controller: one + entry_way: one + last_known_state: MyString + last_state_update: 2025-10-02 12:17:32 + +two: + name: MyString + brand: MyString + model: MyString + serial_number: MyString + access_controller: two + entry_way: two + last_known_state: MyString + last_state_update: 2025-10-02 12:17:32 diff --git a/test/models/access_controller_test.rb b/test/models/access_controller_test.rb new file mode 100644 index 0000000..fb9d4cd --- /dev/null +++ b/test/models/access_controller_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AccessControllerTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/access_path_test.rb b/test/models/access_path_test.rb new file mode 100644 index 0000000..4330d13 --- /dev/null +++ b/test/models/access_path_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AccessPathTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/access_rule_set_test.rb b/test/models/access_rule_set_test.rb new file mode 100644 index 0000000..30c0a66 --- /dev/null +++ b/test/models/access_rule_set_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AccessRuleSetTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/building_test.rb b/test/models/building_test.rb new file mode 100644 index 0000000..179fec1 --- /dev/null +++ b/test/models/building_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class BuildingTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/credential_format_field_bit_test.rb b/test/models/credential_format_field_bit_test.rb new file mode 100644 index 0000000..e34034b --- /dev/null +++ b/test/models/credential_format_field_bit_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class CredentialFormatFieldBitTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/credential_format_field_test.rb b/test/models/credential_format_field_test.rb new file mode 100644 index 0000000..718a9fd --- /dev/null +++ b/test/models/credential_format_field_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class CredentialFormatFieldTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/credential_format_parity_bit_range_test.rb b/test/models/credential_format_parity_bit_range_test.rb new file mode 100644 index 0000000..d1ab27b --- /dev/null +++ b/test/models/credential_format_parity_bit_range_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class CredentialFormatParityBitRangeTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/credential_format_parity_bit_test.rb b/test/models/credential_format_parity_bit_test.rb new file mode 100644 index 0000000..6df1a2f --- /dev/null +++ b/test/models/credential_format_parity_bit_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class CredentialFormatParityBitTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/credential_format_test.rb b/test/models/credential_format_test.rb new file mode 100644 index 0000000..5864447 --- /dev/null +++ b/test/models/credential_format_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class CredentialFormatTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/credential_test.rb b/test/models/credential_test.rb new file mode 100644 index 0000000..3396384 --- /dev/null +++ b/test/models/credential_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class CredentialTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/credential_type_test.rb b/test/models/credential_type_test.rb new file mode 100644 index 0000000..9b51373 --- /dev/null +++ b/test/models/credential_type_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class CredentialTypeTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/entry_way_test.rb b/test/models/entry_way_test.rb new file mode 100644 index 0000000..1296dcc --- /dev/null +++ b/test/models/entry_way_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class EntryWayTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/group_test.rb b/test/models/group_test.rb new file mode 100644 index 0000000..eddbcc8 --- /dev/null +++ b/test/models/group_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class GroupTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/person_test.rb b/test/models/person_test.rb new file mode 100644 index 0000000..357c9af --- /dev/null +++ b/test/models/person_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class PersonTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/reader_test.rb b/test/models/reader_test.rb new file mode 100644 index 0000000..ae2a412 --- /dev/null +++ b/test/models/reader_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ReaderTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/sector_test.rb b/test/models/sector_test.rb new file mode 100644 index 0000000..7ae4626 --- /dev/null +++ b/test/models/sector_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class SectorTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/sensor_test.rb b/test/models/sensor_test.rb new file mode 100644 index 0000000..08c495f --- /dev/null +++ b/test/models/sensor_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class SensorTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end