puemos

puemos

Craftplan - Open-source production management for small manufacturers

My wife was planning to open a micro-bakery and we started looking at software to manage recipes, inventory, orders, and production. Everything was either expensive, too generic, or both. The workflows for a small-batch manufacturer aren’t that complex, but the pricing acts like they are.

So I built Craftplan. All the features were tailored to what she actually needed, and I figured other small-scale manufacturers (soap makers, breweries, candle makers, etc.) probably need the same things. So I’m putting it out there for free.

What it does:

  • Product catalog with versioned recipes (BOMs) and automatic cost rollups across materials, labor, and overhead
  • Inventory tracking with lot traceability, expiry dates, allergen/nutrition flags, and demand forecasting
  • Order processing with calendar-based scheduling and allocation to production batches
  • Production planner with make sheets, material consumption from specific lots, and cost snapshots
  • Purchase orders with receiving workflow that auto-creates inventory lots
  • Basic CRM for customers and suppliers
  • CSV import/export, iCal calendar feed, JSON:API and GraphQL endpoints

Experience building with Elixir, Ash and Liveview

  • Speed: you get to test and improve things sooo fast. The DSL makes it simple to translate your thinking into live product
  • Extensibility: With Ash + LiveView you can add more features so easily. Adding JSON:API + Grapghql was a few minutes.
  • UX: I believe LiveView makes it simple to deliver great UX since it forcing you to keep things simple with no so much interaction overhead which most of the time means better and simple experience

Self-hosting:

Docker image: ghcr.io/puemos/craftplan (amd64 + arm64)

Docker Compose bundles PostgreSQL 16 + MinIO.

curl -O https://raw.githubusercontent.com/puemos/craftplan/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/puemos/craftplan/main/.env.example
cp .env.example .env
docker compose up -d

Other details:

  • Email config from UI (SMTP, SendGrid, Mailgun, Postmark, Brevo, Amazon SES)
  • API keys encrypted at rest (AES-256-GCM)
  • Role-based access (admin/staff)
  • Tech stack: Elixir, Ash Framework, Phoenix LiveView, PostgreSQL
  • License: AGPLv3

Feedback welcome (and needed!)

Most Liked

code-shoily

code-shoily

This looks fantastic. The UI is :+1: . Will take a look at the code later today, hope there’d be a lot for me to learn from! Thank you for building and sharing this.

puemos

puemos

Feel free to ask anything, will be happy to share :slight_smile:

FlyingNoodle

FlyingNoodle

Since you wrote that you welcome feedback. Doing this in a LiveView is not recommended in ash:

Ash.read!(Craftplan.CRM.Customer,
         actor: socket.assigns[:current_user],
         load: [:billing_address, :shipping_address, :full_name]
       )

https://github.com/puemos/craftplan/blob/main/lib/craftplan_web/live/manage/customer_live/index.ex#L63

Instead, you should define idiomatic actions on your resources and domains: Actions — ash v3.29.3

So in this case I would use the Ash action that you already have defined in your domain:

Craftplan.CRM.list_customers!(actor:  socket.assigns.current_user, load: [:billing_address, :shipping_address, :full_name])

Where Next?

Popular in Discussions Top

andre1sk
A big advantage to Elixir is all the distributed goodness but for many applications running on multiple nodes having integrated Etcd, Zoo...
New
blackode
Elixir Upgrading is so Simple in Ubuntu and It worked for me Ubuntu 16.04 git clone https://github.com/elixir-lang/elixir.git cd elixir...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31265 143
New
AstonJ
Are there any Elixir or Erlang libraries that help with this? I’ve been thinking how streaming services like twitch have exploded recentl...
New
Crowdhailer
I’ve been hearing much about the new formatter and it’s something I have been keen to try. I find examples buy far the most illuminating...
248 19327 150
New
mbenatti
Following https://github.com/tbrand/which_is_the_fastest |> https://raw.githubusercontent.com/tbrand/which_is_the_fastest/master/imgs...
New
RudManusachi
What configs will make sense to put to runtime.exs? – A bit of how I configure apps: I have generic configs in config/config.exs, dev...
New
ben-pr-p
In general I’ve been sticking to this community style guide GitHub - christopheradams/elixir_style_guide: A community driven style guide ...
New
Qqwy
Looking at the stacks that existing large companies have used, WhatsApp internally uses Mnesia to store the messages, while Discord uses ...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31265 143
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52673 488
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement