{
"path": "/3ma4mvv3lsk24",
"site": "at://did:plc:dgtaz4vldacvqhvvmdvoc4ad/site.standard.publication/3m7iwa2i6us22",
"tags": [
"jobtrail",
"devlog"
],
"$type": "site.standard.document",
"title": "Jobtrail EP 3: Laravel New'd",
"content": {
"$type": "pub.leaflet.content",
"pages": [
{
"id": "019b2789-c1d5-7338-8a43-92acd3a49b06",
"$type": "pub.leaflet.pages.linearDocument",
"blocks": [
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 37,
"byteStart": 22
},
"features": [
{
"uri": "https://mlogs.leaflet.pub/3m7nirslulc25",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "So I mentioned in the previous devlog that I would make a detailed architecture post; well that just got a whole lot simpler!"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"facets": [],
"plaintext": "The initial architecture"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 57,
"byteStart": 43
},
"features": [
{
"uri": "https://www.better-t-stack.dev/",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "The initial architecture was created using better-t-stack which is an amazing tool to kickstart a js monorepo. The problem with this approach is that you now have a bunch of dependencies that need to be bundled correctly (which better-t-stack already sets up) and - in my usecase - containerized to have the smallest image size."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 353,
"byteStart": 345
},
"features": [
{
"uri": "https://adonisjs.com/",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Then came the biggest issues: mails & scheduled jobs. Don't get me wrong, there are solutions for both in Javascript ecosystem (React Email, bullmq, pgboss and more come to mind) but I felt it would add another layer of complexity the app could probably do without. So the question now became; should I just move the api layer to something like AdonisJS to have a more batteries included setup and where I could easily"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"facets": [],
"plaintext": "The new architecture"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 104,
"byteStart": 97
},
"features": [
{
"uri": "https://laravel.com",
"$type": "pub.leaflet.richtext.facet#link"
}
]
},
{
"index": {
"byteEnd": 178,
"byteStart": 171
},
"features": [
{
"uri": "https://inertiajs.com/",
"$type": "pub.leaflet.richtext.facet#link"
}
]
},
{
"index": {
"byteEnd": 376,
"byteStart": 357
},
"features": [
{
"uri": "https://spatie.be/docs/laravel-data/v4/introduction",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Turns out I know of a framework that has scheduling, mails, queued jobs and more out of the box: Laravel. And I can kind of keep most of my frontend code by using it with Inertia. It's not a 1:1 port by any means, though. I lose out on better-auth and orpc, having to rely on Laravel's auth system and on making the calls typesafe in another way - by using spatie/laravel-data to generate types from my DTOs."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"facets": [],
"plaintext": "The new deployment strategy"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Before, I had multiple docker images that I needed to maintain:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "a helper that ran the migrations if/when there was something new"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "the actual server image"
},
"children": []
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Each of these images needed to have different packages copied inside them for the build step and it was kind of messy - though still manageable."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Now this is not yet finalized, but I think I might be able to either have:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "a single image with different start commands in a docker-compose stack"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 79,
"byteStart": 68
},
"features": [
{
"uri": "https://github.com/just-containers/s6-overlay/tree/master#writing-a-service-script",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "a single image and container with more services defined inside some s6 services"
},
"children": []
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Anyway I'll keep you updated when all of this is finished :)"
}
}
]
}
]
},
"bskyPostRef": {
"cid": "bafyreic66ly6kjdgabvhmlfc2gtswb4j6tivrelkewaq7jsh7s5tnevbne",
"uri": "at://did:plc:dgtaz4vldacvqhvvmdvoc4ad/app.bsky.feed.post/3ma4mvzpvvk22",
"commit": {
"cid": "bafyreiescyrydrpa5yvriu7sqr6kry23zggurybuk6wamuunapktprr57q",
"rev": "3ma4mvzskzz2q"
},
"validationStatus": "valid"
},
"description": "",
"publishedAt": "2025-12-16T17:04:15.370Z"
}