Skip to content

Repository files navigation

AuctionKit

A reusable auction engine for Elixir. It runs more than one product on one engine. The auctioned item is generic. The captured contact details are a generic map that each product defines. The storage backend is a plug-in.

This library holds the hard code: the row locks, the one-pending rule, the raise math, the accept and reject state machine, the daily limit, and the asset upload order. It owns the schemas but not the database. The host app gives the repo and the settings.

Install

Add a git dependency (pin a release tag):

{:auction_kit, github: "oshi-connect/auction_kit", tag: "v0.1.0"}

Config

config :auction_kit,
  repo: MyApp.Repo,
  auction_schema: MyApp.Auction,
  item_schema: MyApp.Item,
  bid_schema: MyApp.Bid,
  storage_impl: AuctionKit.Storage.S3,
  asset_key_prefix: "assets/myapp/",
  max_asset_bytes: 5_000_000,
  allowed_content_types: ~w(image/png image/jpeg image/jpg),
  max_submissions_per_day: 10,
  contact_spec: [
    %{key: "website", required: false, normalize: {AuctionKit.Contact, :website}},
    %{key: "twitter", required: false},
    %{key: "discord", required: false}
  ],
  # Optional. The engine calls this after a write, so you can broadcast.
  on_change: {MyAppWeb.Endpoint, :broadcast_wall}

An existing product can keep its own tables and columns. Override only the names that differ, in AuctionKit.Mapping:

config :auction_kit,
  bid_asset_key_field: :image_key,
  bid_item_fk: :spot_id,
  bid_item_assoc: :spot,
  pending_unique_constraint: "bids_one_pending_per_spot"

Schemas

A greenfield product uses the schema macros. The macros give the generic shape.

defmodule MyApp.Auction do
  use AuctionKit.Schema.Auction, table: "auctions", item_schema: MyApp.Item
end

defmodule MyApp.Item do
  use AuctionKit.Schema.Item,
    table: "items",
    auction_schema: MyApp.Auction,
    bid_schema: MyApp.Bid
end

defmodule MyApp.Bid do
  use AuctionKit.Schema.Bid, table: "bids", item_schema: MyApp.Item
end

Create the tables from a migration:

defmodule MyApp.Repo.Migrations.CreateAuction do
  use Ecto.Migration
  def up, do: AuctionKit.Migrations.up()
  def down, do: AuctionKit.Migrations.down()
end

Use

auction = MyApp.Repo.get_by!(MyApp.Auction, slug: "spring-sale")

AuctionKit.Auctions.place_bid(auction, %AuctionKit.PlaceBid{
  item_id: item_id,
  amount_cents: 2500,
  display_name: "Kai",
  email: "kai@example.com",
  contact: %{"website" => "example.com"},
  asset_bytes: bytes,
  content_type: "image/png"
})

AuctionKit.Auctions.accept_bid(bid_id)
AuctionKit.Auctions.reject_bid(bid_id)
AuctionKit.Auctions.snapshot(auction, codes: ["I01", "I02"], visitor_count: 3)
AuctionKit.Auctions.list_pending_bids()

Storage backends

The store is a plug-in. Pick one with :storage_impl. The engine calls the store only through AuctionKit.Storage, so a product swaps the backend with a config change and no code change.

Adapter Use
AuctionKit.Storage.S3 Cloudflare R2, AWS S3, or MinIO. Needs ex_aws and ex_aws_s3.
AuctionKit.Storage.Postgres A Postgres table, through Postgrex. No extra dependency.
AuctionKit.Storage.Memory An ETS table, for tests and simple setups.

A product may add any module that follows the AuctionKit.Storage behaviour.

For the Postgres backend, add the object table:

def up, do: AuctionKit.Storage.Postgres.Migration.up()

Second product example

The library is general. A second product uses a different contact spec and different item attributes. For example, a standee auction:

config :auction_kit,
  storage_impl: AuctionKit.Storage.Postgres,
  asset_key_prefix: "assets/standee/",
  contact_spec: [
    %{key: "company", required: true},
    %{key: "phone", required: true},
    %{key: "website", required: false, normalize: {AuctionKit.Contact, :website}}
  ]

The item stores its own fields in the attributes map, for example %{"floor" => 2, "aisle" => "A"}.

Test

The library has its own test repo and an Ecto sandbox. It needs a running Postgres.

mix deps.get
mix test

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages