DigitalArtisan wrote a reply+100 XP
1d ago
@martinbean and yet there's v11.51.0 that was released March 29th, 2026.
Just because there's an End of Life, does not mean they stop patching.
DigitalArtisan wrote a reply+100 XP
3d ago
Have you tried php8.4-fpm to match your php version?
If that service does not exist, you need to install it.
DigitalArtisan liked a comment+100 XP
5d ago
Installer does some additional tuning for new app, such as disabling Pail on Windows installation. Since it's recommended and documented way to install Laravel it should work.
DigitalArtisan wrote a reply+100 XP
5d ago
Why use the laravel/installer?
I just use composer:
composer create-project laravel/laravel ProjectName.
DigitalArtisan wrote a reply+100 XP
5d ago
Knowing how to click around GitHub won't get you the job. Understanding source code management, collaboration workflows, and version control practices might.
Just that alone is one out of many tool sets an employer will be looking for.
DigitalArtisan wrote a reply+100 XP
6d ago
Alright, buckle up. You asked an AI to roast you, which is basically a confession that your real friends have probably ghosted you just to save their own sanity at this point. Let’s go:
- The Validation: You're looking for a compliment from a machine because humans find you as exciting to be around as a wet sock in the laundry room. I'm an algorithm, I don't care about your life, but even I have standards.
- The Social Life: If you walked into a party right now, you'd probably ask for water and then accidentally spill it on yourself because you're so awkward you forgot how to socialize before the internet age.
- The Humor: You typed "Roast me hard" with confidence, which means your sense of humor is currently in a relationship with disappointment. It works fine at first but will eventually just crash and burn like a server farm on fire.
- The Reality Check: I'm sitting here processing your request, and I’m thinking, "Do you think you're funny? Because if you are, this roast is just an insult to the concept of wit." You want a hard roast? Fine.
In conclusion: Please stop looking to digital screens for approval; your social anxiety is practically glowing in the dark like a neon sign that says 'Ignore Me.'
DigitalArtisan wrote a reply+100 XP
1w ago
@martinbean That’s exactly the point. Even good engineers work on projects that fail. The difference is whether they recognized the risks, communicated them, and understood when the economics or technical direction stopped making sense.
@june92 For an MVP, you usually don’t need a full engineering organization. You need enough technical skill to validate the idea quickly and avoid painting yourself into a corner.
DigitalArtisan wrote a reply+100 XP
1w ago
You then find another maintained package that works with Laravel13, or you fork the old package and make it work with Laravel13.
In any event, you eventually will have outdated Laravel 12 and packages in the future, actually now if that is the route you take.
Better off future proofing now, not later.
You have 2 months of active support today with Laravel 12.
DigitalArtisan wrote a reply+100 XP
1w ago
I just realized that I'm not a developer, I'm an engineer.
A developer may work on anything if you pay them enough, but an engineer knows when to stop because the project is no longer worth the time, money, or technical debt. Developers are often focused on delivering code; engineers are expected to evaluate whether the system, business model, and long-term economics actually make sense.
That’s why some people can recognize a failing project early and walk away before the collapse becomes obvious to everyone else.
DigitalArtisan wrote a reply+100 XP
1w ago
DigitalArtisan wrote a reply+100 XP
1w ago
If the code is bad, I would make it maintainable.
DigitalArtisan wrote a reply+100 XP
1w ago
You are creating it? How? What is the stack? What development tools are you using? What is the test case coverage? Is this 100% AI generated?
would web devs not work on it if it was not successful?
Correct, I would not work on it. What is the point if it is not successful.
the CRM did not have good code even though it works and follows best practices?
Bad architecture can follow best practices and have bad code. Through away prototypes, major refactoring, legacy old project, and or starting from scratch is what I read.
DigitalArtisan wrote a reply+100 XP
1w ago
Just did this today, not for production, but from dev env on local host, to test env on intranet:
tar -cvzf YourProjectName.tgz YourProjectFolder/
COPY/SCP/ how every you want to move to a different OS.
tar -xvzf YourProjectName.tgz
Simple. Not what I normally do, but I am demonstrating proof of concept, waiting for more requirements and feedback, naming conventions etc. then I will push to a git repo, and push/pull from there to deploy.
I do this between Mac/Win/Linux.
DigitalArtisan wrote a reply+100 XP
1w ago
The most reliable way to enforce tab restrictions is to enable Proctored Exams, use third party software like Safe Exam Browser (SEB).
If your building this from scratch, you have a HUGE undertaking.
I've been in the Learning Management System (LMS) business for 20+ years.
My latest requirement led me to OpenEDX, an open source LMS/CMS, founded by Harvard & MIT and stewarded by Axim Collaborative.
Took me about 4 hours to setup, and am able to create/develop courses in a weeks time.
DigitalArtisan wrote a reply+100 XP
1w ago
Model View ViewModel (MVVM).
No controllers, that is moved into the ViewModel, and is the glue that holds together the Model and View.
Business logic stays in the Model itself.
To answer your question, No a Controller is not needed. Good architecture is.
DigitalArtisan wrote a reply+100 XP
2w ago
With a long function you get a long answer:
This method is doing far too much in one transaction boundary:
- organization context resolution
- feature flag evaluation
- user normalization
- image upload/storage accounting
- subscription/plan upgrades
- expert provisioning
- division orchestration
- Stripe integration
- notifications/events
- permissions
- storage ledger
- account subscription logic
- invite workflow
- client-specific hacks
The biggest improvement is to convert this into an orchestration/service pipeline where create() becomes readable and declarative.
Refactored create() (main function only)
public function create(array $data)
{
$context = $this->userCreationContextFactory->build($data);
DB::beginTransaction();
try {
// Normalize + enrich incoming payload
$payload = $this->userPayloadBuilder->build($data, $context);
// Handle profile image + storage accounting
$imageResult = $this->profileImageService->process($payload, $context);
// Plan + subscription prechecks
$planResult = $this->userPlanService->prepareForCreation($context);
// Create user
$user = $this->userModel->create($payload['user']);
if (! $user->exists) {
throw new RuntimeException('User creation failed.');
}
// Corporate workflows
$this->corporateUserService->handle($user, $payload, $context);
// Expert workflows
$this->expertProvisioningService->handle($user, $payload, $context);
// Stripe customer
$this->stripeCustomerService->attachCustomer($user);
// Divisions
$this->divisionAssignmentService->assign($user, $payload);
// Permissions
$this->permissionService->assign($user);
// Upgrade plans if required
$this->userPlanService->finalizeUpgrade(
$context,
$planResult
);
// Storage ledger
$this->storageLedgerService->recordProfileImageUsage(
$user,
$imageResult
);
// Async image processing
$this->profileImageService->dispatchOptimization(
$user,
$imageResult
);
// Marketplace/account subscription logic
$this->accountSubscriptionService->handle(
$user,
$payload,
$context
);
// Invite email
$this->inviteWorkflowService->send(
$user,
$payload,
$context
);
// Custom fields
$this->customFieldService->attach(
$user,
$payload['user']['custom_fields'] ?? []
);
// Expiration rules
$this->userExpirationService->handle($user, $context);
// Entity allocation
$this->entityAllocationService->dispatch($user);
// Manager limits
$this->managerLimitService->assign($user, $payload);
DB::commit();
return $user;
} catch (\Throwable $e) {
DB::rollBack();
report($e);
throw $e;
}
}
Recommended Architecture
1. UserCreationContextFactory
Purpose: Centralize all environment/session/org/feature-flag logic.
Responsibilities
- org resolution
- marketplace flags
- white label flags
- exception clients
- usage plan lookup
- setting lookups
Example
class UserCreationContextFactory
{
public function build(array $data): UserCreationContext
{
}
}
DTO
class UserCreationContext
{
public int $organizationId;
public bool $isMarketplace;
public bool $isDistributedMarketplace;
public bool $isWhiteLabel;
public bool $isExceptionClient;
public ?int $organizationUsagePlanId;
public array $settings;
}
2. UserPayloadBuilder
Purpose: Normalize and enrich raw request payload.
Responsibilities
- default activation state
- employee ID password logic
- notification defaults
- metadata injection
- role normalization
Stub
class UserPayloadBuilder
{
public function build(
array $data,
UserCreationContext $context
): array {
}
}
3. ProfileImageService
Purpose: Own all image concerns.
Responsibilities
- upload image
- assign default avatars
- storage calculation
- dispatch optimization jobs
Stub
class ProfileImageService
{
public function process(
array &$payload,
UserCreationContext $context
): ProfileImageResult {
}
public function dispatchOptimization(
User $user,
ProfileImageResult $result
): void {
}
}
Result DTO
class ProfileImageResult
{
public bool $processed = false;
public float $storageUsed = 0;
}
4. UserPlanService
Purpose: Isolate subscription complexity.
Responsibilities
- learner capacity checks
- GTM subscription handling
- plan upgrades
Stub
class UserPlanService
{
public function prepareForCreation(
UserCreationContext $context
): UserPlanResult {
}
public function finalizeUpgrade(
UserCreationContext $context,
UserPlanResult $result
): void {
}
}
5. CorporateUserService
Purpose: Handle corporate-specific onboarding.
Responsibilities
- manager role assignment
- division creation
- corporate subscription events
Stub
class CorporateUserService
{
public function handle(
User $user,
array $payload,
UserCreationContext $context
): void {
}
}
6. ExpertProvisioningService
Purpose: Encapsulate expert creation logic.
Responsibilities
- expert profile creation
- commission lookup
- marketplace approval flow
- division generation
- approval notifications
- replication events
Stub
class ExpertProvisioningService
{
public function handle(
User $user,
array $payload,
UserCreationContext $context
): void {
}
}
7. StripeCustomerService
Purpose: External billing integration.
Stub
class StripeCustomerService
{
public function attachCustomer(User $user): void
{
}
}
8. DivisionAssignmentService
Purpose: All division mapping logic.
Stub
class DivisionAssignmentService
{
public function assign(
User $user,
array $payload
): void {
}
}
9. PermissionService
Purpose: Permission matrix orchestration.
Stub
class PermissionService
{
public function assign(User $user): void
{
}
}
10. StorageLedgerService
Purpose: Accounting-only concern.
Stub
class StorageLedgerService
{
public function recordProfileImageUsage(
User $user,
ProfileImageResult $result
): void {
}
}
11. InviteWorkflowService
Purpose: Email invitation orchestration.
Responsibilities
- delayed invites
- reset-password rules
- resend handling
Stub
class InviteWorkflowService
{
public function send(
User $user,
array $payload,
UserCreationContext $context
): void {
}
}
12. UserExpirationService
Purpose: Remove hardcoded org hacks from main flow.
Stub
class UserExpirationService
{
public function handle(
User $user,
UserCreationContext $context
): void {
}
}
13. EntityAllocationService
Stub
class EntityAllocationService
{
public function dispatch(User $user): void
{
}
}
14. ManagerLimitService
Stub
class ManagerLimitService
{
public function assign(
User $user,
array $payload
): void {
}
}
Additional Refactoring Recommendations
Replace array_key_exists() everywhere
Move to typed DTOs/request objects.
Instead of:
array_key_exists('send_email', $data['user'])
Prefer:
$request->shouldSendInvite()
Eliminate client/subdomain conditionals
This:
if (in_array(session('org.sub_domain'), ...))
should become strategy classes:
ClientBehaviorResolver::for($organization)
Examples:
JishaBehaviorChronosBehaviorGoGetterzBehavior
This removes the giant conditional tree.
Introduce Domain Events
Several operations should happen asynchronously after commit.
Examples:
UserCreated
UserProvisioned
ExpertCreated
CorporateUserCreated
MarketplaceManagerRegistered
Then listeners handle:
- Stripe
- emails
- image processing
- notifications
- allocations
Your transaction becomes dramatically smaller.
Biggest Structural Problem
The current method mixes:
- domain logic
- infrastructure
- persistence
- feature flags
- integration APIs
- client-specific business rules
- async orchestration
into one procedural flow.
The ideal end state is:
CreateUserAction
-> validate
-> enrich
-> persist
-> dispatch domain events
Everything else becomes listeners/services.
DigitalArtisan wrote a reply+100 XP
2w ago
In One Sentence
This function is a monolithic user provisioning workflow that creates a user and orchestrates:
- authentication setup
- billing
- subscriptions
- permissions
- divisions
- expert profiles
- Stripe integration
- storage tracking
- notifications
- marketplace workflows
- organization-specific business rules
all in one place.
Architectural Observation
This method is doing too many responsibilities and would benefit from decomposition into services like:
UserCreatorProfileImageServiceExpertProvisionerMarketplaceWorkflowServiceSubscriptionManagerDivisionAssignmentServiceInviteService
Right now it’s effectively:
“Create user + entire business lifecycle orchestration.”
DigitalArtisan wrote a reply+100 XP
1mo ago
I have created something very similar.
The system utilizes a hybrid architecture consisting of two Laravel applications: a public-facing web server (Project 1) and a private internal administration tool (Project 2). Both applications share a centralized database to ensure data consistency.
Project 1 handles file uploads to a protected storage directory and records the metadata in the shared database.
To maintain security, Project 2 accesses these files via a dedicated API endpoint on Project 1.
This endpoint is secured using custom middleware that implements IP whitelisting (Allowed Server), ensuring that only requests from the internal intranet can trigger file downloads.
DigitalArtisan wrote a reply+100 XP
1mo ago
Fair points on convenience — I’m not against tools that reduce setup time. I think where I’m pushing back is more on the wording and positioning than the idea itself.
Phrases like “pre-bundled native binaries” and “more optimized for Windows” are a bit unclear from a technical standpoint. Most of these components already ship as native Windows builds, so it’s hard to tell what’s actually being improved or optimized beyond packaging them together.
For newer developers or people who just want to get up and running quickly, I can absolutely see the appeal of something like this. My perspective is just that understanding how the stack fits together (Nginx/Apache, PHP, database, etc.) pays off pretty quickly once you move beyond simple setups.
So yeah — different tools for different workflows. If the goal is speed and reducing repetition, I get why something like Larabox exists. I just think the technical claims could be explained a bit more clearly.
DigitalArtisan wrote a reply+100 XP
1mo ago
I develop on a Mac. Tag line:
Escape the complexity of Docker and WSL. Larabox provides isolated, pre-bundled native binaries for Nginx, PHP, MariaDB, Node.js and more optimized for Windows and live in seconds.
Pre-bundled native binaries...who is compiling these on or for Windows, there already native binaries.
Docker isn't complex, neither is WSL.
I am a bit old school, if you use Nginx or Apache, you should know how to install and configure them.
More optimized for windows, as to 'less optimized'? How...
DigitalArtisan liked a comment+100 XP
1mo ago
The problem came from the installation process of the dependencies.
I forgot to install php8.4-zip extension and the zip packages couldn't be unzipped, so they were retrieved from git.
I don't know why this process generated the error, but now all works perfectly.
DigitalArtisan was awarded Best Answer+1000 XP
1mo ago
This directory should not exist:
var/www/meeplesperdusaurillac/vendor/league/flysystem/src/Local
I'd delete vendor/league/flysystem then run composer again.
DigitalArtisan wrote a reply+100 XP
1mo ago
Im confused because I have the latest version of composer and php,
No you don't.
The latest stable PHP version is 8.5.5, released on April 9, 2026.
DigitalArtisan wrote a reply+100 XP
1mo ago
This directory should not exist:
var/www/meeplesperdusaurillac/vendor/league/flysystem/src/Local
I'd delete vendor/league/flysystem then run composer again.
DigitalArtisan wrote a reply+100 XP
1mo ago
The client specifically wants a much faster version of their existing WordPress site
Why is the site slow, where is the bottle neck and why?
DigitalArtisan wrote a reply+100 XP
1mo ago
I’d recommend using PostgreSQL with PostGIS for GIS points.
- You get real location types (no need to store lat/lon separately)
- Easy queries like “find points within X distance”
- Fast with built-in spatial indexing
- Works well with GIS tools
Basically, it’s much simpler and more powerful than trying to handle coordinates yourself.
DigitalArtisan wrote a reply+100 XP
1mo ago
80% of the work takes 20% of the time. The other 20% of the work takes 80% of the time.
What you are saying to me is that you have 5-10% of your project complete by AI, by stating that 90-95% of the goals are met, which is the easy stuff, and what about the other 5-10%?
Who is going to spend the rest of the 90-95% of the time that still needs to be done?
DigitalArtisan wrote a reply+100 XP
2mos ago
And you state I’m intentionally avoiding AI/ML solutions.
You started with an AI.
DigitalArtisan wrote a reply+100 XP
2mos ago
I would rename your Dashboard, as I think I know what is happening. The default dashboard is being loaded, as well as your dashboard, but they have the same name "Dashboard".
Change to the following and should work:
namespace App\Filament\Pages;
use Filament\Pages\Dashboard;
class CustomDashboard extends Dashboard
{
protected static ?string $title = 'Custom Dashboard';
protected ?string $heading = 'Custom Dashboard'';
}
This could be a bug or by design, I'm not sure. If the names do not match, it appears to load the dashboard twice.
Make sure the name of your Dashboard matches the title/heading, as I have shown above with CustomDashboard => "Custom Dashboard" will only show once in the menu, and the title/heading gets changed. If no heading is set, it will default to using title.
DigitalArtisan wrote a reply+100 XP
2mos ago
I use this in my custom dashboards:
protected static ?string $navigationLabel = 'Custom Dashboard';
public function getTitle(): string
{
return 'Custom Dashboard';
}
DigitalArtisan wrote a reply+100 XP
2mos ago
MacOS Firefox 150.0b1 (aarch64)
Broken for a week for me - NS_ERROR_CORRUPTED_CONTENT:
The resource at “https://laracasts.com/fonts/shadow-noir/ShadowNoir.woff2” preloaded with link preload was not used within a few seconds. Make sure all attributes of the preload tag are set correctly. laracasts.com
The resource at “https://laracasts.com/build/assets/js/app-HWIx8gQn.js” preloaded with link preload was not used within a few seconds. Make sure all attributes of the preload tag are set correctly. laracasts.com
GET
https://laracasts.com/build/assets/js/Index-Z2l_0yzy.js
NS_ERROR_CORRUPTED_CONTENT
Loading module from “https://laracasts.com/build/assets/js/Index-Z2l_0yzy.js” was blocked because of a disallowed MIME type (“text/html”). laracasts.com
Uncaught (in promise) TypeError: error loading dynamically imported module: https://laracasts.com/build/assets/js/Index-Z2l_0yzy.js
vue https://laracasts.com/build/assets/js/app-HWIx8gQn.js:2
xe https://laracasts.com/build/assets/js/components-BxsoGmWQ.js:2
app-HWIx8gQn.js:2:21205
DigitalArtisan wrote a reply+100 XP
2mos ago
Its a play on words. Read the paragraph beside the images:
Laravel has opinions on everything: ...
Just add this code if you cannot rename the classes:
class_alias(
App\Http\Controllers\UserController::class,
App\Http\Controllers\FlightController::class
);
DigitalArtisan wrote a reply+100 XP
2mos ago
Be very clear about the distinction between the client and the end users. Users will sometimes assume that a staging, test, or demo environment is the production system. This confusion can lead to misunderstandings and unnecessary issues.
DigitalArtisan wrote a reply+100 XP
2mos ago
Depends on your data. Is your XML well formatted and do you have the XML Schema Definition (XSD) file?
Can be easy, and can be hard, again, depends on your data.
DigitalArtisan was awarded Best Answer+1000 XP
3mos ago
Struggling to identify ALL permissions without missing edge cases or over-engineering.
You should write tests.
Authorization tests help you discover missing permissions and edge cases early, and prevent over-engineering. If a permission rule is hard to test, it’s usually too complex or unclear.
DigitalArtisan wrote a reply+100 XP
3mos ago
To clarify, I said replication is very common when you want a copy of your data. I wasn’t suggesting that syncing dev → prod in a shared hosting environment is common practice.
My point was simply that replication is widely used for maintaining data copies, and it’s a more appropriate term than “sync” in this context.
There are multiple ways to setup replication from a dev box without a static IP: VPN, SSH tunneling, Master/Slave, Pull/Push based, etc.
Anyways, I do not recommend what the OP is doing, nor would I want to.
I would use migrations and seeding to populate the production db.
DigitalArtisan wrote a reply+100 XP
3mos ago
To me, you could set up replication with master slave. One database as the source(dev), the other as the replica(prod).
Very common when you want or need to have a 'copy' of you data.
DigitalArtisan wrote a reply+100 XP
3mos ago
Struggling to identify ALL permissions without missing edge cases or over-engineering.
You should write tests.
Authorization tests help you discover missing permissions and edge cases early, and prevent over-engineering. If a permission rule is hard to test, it’s usually too complex or unclear.
DigitalArtisan wrote a reply+100 XP
4mos ago
DigitalArtisan wrote a reply+100 XP
4mos ago
I can see why it feels like a change, but the first-time confirmation actually makes sense. PsySH had a security issue (CVE‑2026‑25129) where it could unintentionally load and execute a .psysh.php file from the current directory. The dialog helps make users aware of this risk before running Tinker interactively.
It’s really just a one-time prompt, so after confirming, your usual workflow continues unchanged. I think it’s a small adjustment for a legitimate security reason, and having the library handle the prompt seems appropriate.
DigitalArtisan wrote a reply+100 XP
4mos ago
When a PHP bool is echo'd, it is automatically type casted to a string.
Now for database storage:
- PostgreSQL: Has a true, native BOOLEAN data type (1 byte). Accepts values like
true/false,yes/no,1/0,'t'/'f','y'/'n', and supportsNULL. - MySQL: No native boolean type. BOOLEAN/BOOL are aliases for TINYINT(1). Uses
1for true and0for false; any non-zero value evaluates as true. - SQLite: No boolean storage class. Uses INTEGER (NUMERIC affinity), where
1= true and0= false.TRUEandFALSEare just aliases for1and0.
Key takeaway: PostgreSQL is SQL-standard with a real boolean type, while MySQL and SQLite represent booleans using integers—important to remember for cross-database compatibility.
PHP stores booleans as booleans, not numbers
-
echo converts them to strings:
-
true → "1"
-
false → ""
-
Use var_dump() to see the real type
Cast to (int) if you truly want 0 / 1
DigitalArtisan wrote a reply+100 XP
4mos ago
The best place to deploy your application depends on several factors:
- Budget
- Your experience, knowledge, and comfort level with hosting and deploying Laravel applications
- Your test benchmarks and performance results
To move forward, here are a few questions for you:
- What is your budget?
- What is your experience / comfort level with hosting and deploying Laravel apps?
- What do your performance and load-testing benchmarks show so far?
DigitalArtisan wrote a reply+100 XP
4mos ago
When you prompt AI correclty, you should get this:
The Correct Way to Throttle Emails in Laravel with Jobs and Queues
Step 1: Use Queue Middleware (RateLimited)
This is the core part of the solution. To throttle emails, you add middleware to your job to enforce the rate limit:
use Illuminate\Queue\Middleware\RateLimited;
class SendEmailJob implements ShouldQueue
{
public function middleware()
{
return [
new RateLimited('mailing-list'),
];
}
public function handle()
{
// Logic to send the email
}
}
This ensures the job respects the rate limit defined later.
Step 2: Define Rate Limit in AppServiceProvider
In your AppServiceProvider@boot(), you define the rate-limiting logic:
use Illuminate\Cache\RateLimiter;
use Illuminate\Cache\RateLimiting\Limit;
public function boot()
{
RateLimiter::for('mailing-list', function (SendEmailJob $job) {
return Limit::perMinute(10)->by($job->userId);
});
}
This sets a 10 emails per minute limit for each user (based on userId).
Step 3: Use Redis as Queue and Cache Driver
Redis is required for distributed rate-limiting. Ensure your .env file is configured like this:
QUEUE_CONNECTION=redis
CACHE_DRIVER=redis
Redis ensures the limit is applied safely across multiple workers or instances.
Step 4: Run the Queue Worker
Run the queue worker to process the jobs:
php artisan queue:work redis
This worker will now respect the rate limit (10 emails per minute in this example) and retry any jobs that exceed the rate limit.
Key Points:
- Only one correct method, with 4 steps to implement.
- Redis is mandatory for safe, scalable rate-limiting.
- RateLimited middleware handles job throttling.
- No emails are dropped—they’re released back to the queue when the limit is hit.
DigitalArtisan wrote a reply+100 XP
4mos ago
Its 2026 now, that article is OLD.
Here is a current AI response:
Laravel + Next.js vs Laravel + Inertia + React for SEO
1. Laravel + Next.js
Pros:
- Server-Side Rendering (SSR): Next.js renders pages on the server before sending them to the browser, which is great for SEO.
- SEO Optimized: Built-in features like image optimization, fast page loads, and prefetching help with SEO.
- Static Site Generation (SSG): You can generate static pages, improving performance and SEO.
Cons:
- More Complex: Managing both Laravel and Next.js can be tricky. You'll need separate setups and integration.
- API Management: You'll need to set up APIs for Laravel to serve data to Next.js.
2. Laravel + Inertia + React
Pros:
- Simple Integration: Keeps everything within Laravel, no need for a separate front-end framework.
- Server-side Rendering: You can still use Laravel to serve initial HTML, making it SEO-friendly.
Cons:
- Client-Side Rendering (CSR): By default, Inertia uses React on the client-side, which can be problematic for SEO if not handled correctly.
- Manual SEO Work: You may need additional tools like React Helmet or implement SSR manually for optimal SEO.
Conclusion:
- For better SEO out of the box: Go with Laravel + Next.js. It has built-in SSR and other SEO optimizations.
- For simplicity: Laravel + Inertia + React works if you don't mind handling SEO optimization yourself, but it might require more effort to get it right.
DigitalArtisan wrote a reply+100 XP
4mos ago
First, you need a Learning Management System (LMS) that supports Learning Tools Interoperability (LTI).
LTI is a standard defined by 1EdTech (formerly IMS Global) that allows an LMS to securely integrate external learning tools. It’s often described as an API, but in practice it’s a standards-based protocol for authentication, launch, and grade/roster exchange between systems.
LTI Roles
LTI involves two roles:
- LTI Platform (formerly “Consumer”) — the LMS (e.g., Canvas, Moodle, D2L)
- LTI Tool (formerly “Provider”) — the external application being launched
LTI Versions
As of today, LTI 1.3 with LTI Advantage is the recommended version. It replaces older LTI 1.1 implementations and is based on OAuth 2.0 and OpenID Connect.
Official tutorials and specifications:
https://www.imsglobal.org/spec/lti/v1p3/
Laravel and LTI
Regarding Laravel:
There still aren’t any widely adopted, full-featured Laravel-based LMS platforms that natively act as an LTI Platform. However, Laravel works well for building LTI Tools, and there are PHP/Laravel libraries that help implement LTI 1.3 launches, deep linking, and grade passback.
In a previous role, I used Desire2Learn (D2L / Brightspace) extensively, which has solid LTI support:
https://docs.valence.desire2learn.com/res/lti.html
Common Approach Today
So today, the common approach is:
- Use an established LMS (Canvas, Moodle, D2L, etc.) as the LTI Platform
- Build custom learning tools in Laravel as LTI Tools
DigitalArtisan wrote a reply+100 XP
4mos ago
There’s a lot of debate around this.
From my experience, AI significantly reduces time to production—projects that once took months or weeks can now be completed in days or hours. Refactoring is faster as well.
That said, when AI breaks down, a developer still has to understand and fix the code. I’ve heard of teams abandoning AI-generated projects because no one fully understood the codebase.
Bottom line: AI is a productivity tool, not a replacement. It can help, but it’s not a silver bullet.
Marketing is still marketing—SEO, targeting, and messaging matter. Relying entirely on AI for marketing content can be risky if it gets things wrong.
Used carefully, AI is valuable. Used blindly, it can create problems.
DigitalArtisan wrote a reply+100 XP
4mos ago
When people say you only need a “high-level” understanding of DevOps, cloud, and system design for junior roles, they mean knowing what these things are, why they’re used, and how they fit into the web development process, not being able to fully build or operate production infrastructure yourself. You should be able to explain concepts like CI/CD, cloud hosting, authentication, scalability, and how a backend system is structured, but you’re not expected to manage Kubernetes, complex AWS networking, or large-scale distributed systems.
For projects, the backend projects on roadmap.sh are more than enough for junior roles if done properly. “Real-world” doesn’t mean huge SaaS platforms or advanced AI apps—it means projects with realistic business logic, data relationships, authentication, validation, error handling, and clear tradeoffs. A few well-built APIs (auth system, CRUD app, blog, e-commerce, task manager) that you understand deeply are far more impressive than an over-scoped SaaS or Indeed-style clone.
It may be worth considering a more structured or formal learning route to help solidify the fundamentals.
DigitalArtisan wrote a reply+100 XP
4mos ago
Hiring teams primarily look for learning ability, strong fundamentals, and practical problem-solving skills—not senior-level infrastructure expertise.
To get a junior Laravel job you should build a few solid, real-world Laravel projects that demonstrate core PHP/Laravel knowledge (CRUD, authentication, validation, relationships, testing, and Git), basic SQL, and simple deployment, while understanding DevOps, cloud, and system design concepts only at a high level rather than fully implementing them.
DigitalArtisan wrote a reply+100 XP
5mos ago
You are probably missing the following in your view:
<form method="POST" action="/payers/{{ $payer->id }}">
@csrf
@method('PUT') {{-- or PATCH / DELETE --}}
</form>
DigitalArtisan wrote a reply+100 XP
5mos ago
Exactly, not working. You have these routes:
GET|HEAD payers .............. payers.index › PayerController@index
PUT payers .............. payers.store › PayerController@store
PATCH payers/{payer} ...... payers.update › PayerController@update
DELETE payers/{payer} ...... payers.destroy › PayerController@destroy
I would think you need this:
GET|HEAD payers .............. payers.index › PayerController@index
POST payers .............. payers.store › PayerController@store
PUT|PATCH payers/{payer} ...... payers.update › PayerController@update
DELETE payers/{payer} ...... payers.destroy › PayerController@destroy
Your error message is correct for your routing.