dwyl / auth

🚪 🔐 UX-focussed Turnkey Authentication Solution for Web Apps/APIs (Documented, Tested & Maintained)
https://authdemo.fly.dev
GNU General Public License v2.0
131 stars 9 forks source link

Chore: Use `statuses` [in-memory] in `auth` #245

Open nelsonic opened 1 year ago

nelsonic commented 1 year ago

At present, because of the way Ecto pre-loads the statuses we get this kind of noise:

Auth.Init.create_admin() #=> %Auth.Person{
  __meta__: #Ecto.Schema.Metadata<:loaded, "people">,
  id: 1,
  auth_provider: email,
  email: "nelson@gmail.com",
  email_hash: <<24, 6, 14, 24, 133, 123, 3, 65, 140, 62, 139, 32, 123, 55, 54,
    233, 140, 190, 125, 85, 217, 184, 140, 67, 115, 14, 165, 165, 250, 147, 167,
    19>>,
  familyName: nil,
  givenName: "Neo",
  locale: "en",
  password: nil,
  password_hash: nil,
  picture: nil,
  username: nil,
  username_hash: nil,
  status: 1,
  tag: nil,
  key_id: nil,
  app_id: nil,
  github_id: nil,
  roles: [
    %Auth.Role{
      __meta__: #Ecto.Schema.Metadata<:loaded, "roles">,
      id: 1,
      desc: "With great power comes great responsibility",
      name: "superadmin",
      person_id: 1,
      app_id: nil,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    }
  ],
  groups: #Ecto.Association.NotLoaded<association :groups is not loaded>,
  statuses: [
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 1,
      text: "verified",
      desc: "People are verified once they confirm their email address",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 2,
      text: "uncategorized",
      desc: "All items are uncategorized when they are first created. (Yes, US spelling)",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 3,
      text: "active",
      desc: "An App, Item or Person can be active; this is the default state for an App",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 4,
      text: "done",
      desc: "Items marked as done are complete",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 5,
      text: "flagged",
      desc: "A flagged App, Item or Person requires admin attention",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 6,
      text: "deleted",
      desc: "Soft-deleted items that no longer appear in UI but are kept for audit trail purposes",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 7,
      text: "pending",
      desc: "When an email or item is ready to be started/sent is still pending",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 8,
      text: "sent",
      desc: "An email that has been sent but not yet opened",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 9,
      text: "opened",
      desc: "When an email is opened by the recipient",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 10,
      text: "bounce_transient",
      desc: "Temporary email bounce e.g. because inbox is full",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 11,
      text: "bounce_permanent",
      desc: "Permanent email bounce e.g. when inbox doesn't exist",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 200,
      text: "OK",
      desc: "successful HTTP request",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 307,
      text: "Temporary Redirect",
      desc: "the request should be repeated with another URI",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 308,
      text: "Permanent Redirect",
      desc: "all future requests should be directed to the given URI",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 400,
      text: "Bad Request",
      desc: "server cannot or will not process the request due to an apparent client error",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 401,
      text: "Unauthorized",
      desc: "when authentication is required and has failed",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 403,
      text: "Forbidden",
      desc: "request forbidden",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 404,
      text: "Not Found",
      desc: "requested resource could not be found",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 429,
      text: "Too Many Requests",
      desc: "has sent too many requests in a given amount of time",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    },
    %Auth.Status{
      __meta__: #Ecto.Schema.Metadata<:loaded, "status">,
      id: 500,
      text: "Internal Server Error",
      desc: "an unexpected condition was encountered",
      person_id: 1,
      person: #Ecto.Association.NotLoaded<association :person is not loaded>,
      inserted_at: ~N[2022-11-07 11:43:50],
      updated_at: ~N[2022-11-07 11:43:50]
    }
  ],
  inserted_at: ~N[2022-11-07 11:43:50],
  updated_at: ~N[2022-11-07 11:43:50]
}

This is super noisy/annoying when trying to debug.

So ... rather than storing the statuses in the DB, I propose we use the dwyl/statuses package we recently created and remove the status schema/table from the auth project!

Todo

The Entity Relationship Diagram (ERD) currently looks like this: erd-before-groups-with-statuse

The statuses table isn't particularly big:

image

But the more I look at it and think about how infrequently it will be updated, the more I think it should just be a static Map that is compiled and in-memory instead of requiring a DB JOIN for every query! ⏳