Skip to content

feat(ideas): add private draft crud#43

Merged
ibourgeois merged 3 commits into
mainfrom
codex/22-ideas-editor
Apr 10, 2026
Merged

feat(ideas): add private draft crud#43
ibourgeois merged 3 commits into
mainfrom
codex/22-ideas-editor

Conversation

@ibourgeois
Copy link
Copy Markdown
Contributor

Closes #22\n\nAdds private draft CRUD for the Ideas app:\n- authenticated users can create, edit, and delete their own drafts\n- ideas are owned by the current user and stay private by default\n- ownership is enforced by policy\n- includes Pest coverage for create/edit/update/delete and unauthorized access

Copilot AI review requested due to automatic review settings April 10, 2026 10:46
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds authenticated, owner-scoped CRUD for private “Idea” drafts in the Ideas app, enforcing ownership via a policy and providing UI for creating/editing/deleting drafts.

Changes:

  • Introduces IdeaController with resource routes for draft CRUD (excluding show) behind auth.
  • Adds IdeaPolicy and registers it to enforce per-user ownership for update/delete.
  • Adds create/edit views and shared form partial; updates index UI with “New idea” and “Edit” affordances; expands UI components (button, textarea) to support these flows.
  • Adds Pest feature coverage for create/edit/update/delete and unauthorized access.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Feature/Ideas/IdeasDraftCrudTest.php Feature tests covering owner CRUD and forbidden access for non-owners.
routes/web.php Replaces ideas index closure with resource routes to IdeaController.
app/Http/Controllers/IdeaController.php Implements index/create/store/edit/update/destroy with Gate authorization.
app/Policies/IdeaPolicy.php Adds ownership-based authorization rules for Idea drafts.
app/Providers/AppServiceProvider.php Registers the IdeaPolicy for the Idea model.
resources/views/ideas/index.blade.php Adds “New idea” action and per-idea “Edit” link.
resources/views/ideas/create.blade.php New draft creation page using shared form partial.
resources/views/ideas/edit.blade.php Draft edit + delete UI using shared form partial.
resources/views/ideas/_form.blade.php Shared create/edit form partial.
resources/views/components/ui/textarea.blade.php Adds value prop support for textarea content.
resources/views/components/ui/button.blade.php Adds as prop to render as anchor or button.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +39 to +43
$validated = $request->validate([
'title' => ['required', 'string', 'max:255'],
'summary' => ['required', 'string', 'max:500'],
'details' => ['required', 'string'],
]);
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The draft workflow/issue text mentions saving partial work, and the ideas table allows summary/details to be NULL, but the store validation currently requires both fields. This prevents creating a minimal draft (e.g., title-only) and forces users to fill everything upfront. Consider making summary/details nullable/optional in validation (and handling empty strings consistently) so partial drafts can be saved.

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +68
$validated = $request->validate([
'title' => ['required', 'string', 'max:255'],
'summary' => ['required', 'string', 'max:500'],
'details' => ['required', 'string'],
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update validation requires summary and details, which means users cannot progressively fill in a draft or clear a field once saved. If drafts are intended to support partial/incremental writing, make these fields optional on update as well (and decide whether an empty string should be stored as NULL).

Suggested change
$validated = $request->validate([
'title' => ['required', 'string', 'max:255'],
'summary' => ['required', 'string', 'max:500'],
'details' => ['required', 'string'],
$request->merge([
'summary' => $request->input('summary') === '' ? null : $request->input('summary'),
'details' => $request->input('details') === '' ? null : $request->input('details'),
]);
$validated = $request->validate([
'title' => ['required', 'string', 'max:255'],
'summary' => ['nullable', 'string', 'max:500'],
'details' => ['nullable', 'string'],

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +13
<x-ui.input label="Summary" name="summary" :value="old('summary', $idea?->summary)" required />
<x-ui.textarea label="Details" name="details" rows="10" required :value="old('details', $idea?->details)" />
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The form marks Summary and Details as required, which locks the UI into the same limitation as the controller validation. If drafts should allow partial saves (e.g., title-only), consider removing required here and letting validation rules drive what’s mandatory.

Suggested change
<x-ui.input label="Summary" name="summary" :value="old('summary', $idea?->summary)" required />
<x-ui.textarea label="Details" name="details" rows="10" required :value="old('details', $idea?->details)" />
<x-ui.input label="Summary" name="summary" :value="old('summary', $idea?->summary)" />
<x-ui.textarea label="Details" name="details" rows="10" :value="old('details', $idea?->details)" />

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +24
public function view(User $user, Idea $idea): bool
{
return $idea->user->is($user);
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These policy checks use $idea->user->is($user), which will lazy-load the user relationship during authorization (extra query per request) when it isn’t already loaded. Since ownership is stored on the model, comparing $idea->user_id === $user->id avoids the query and keeps auth checks cheap.

Copilot uses AI. Check for mistakes.
@ibourgeois ibourgeois merged commit cceeaa8 into main Apr 10, 2026
1 check passed
@ibourgeois ibourgeois deleted the codex/22-ideas-editor branch April 10, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(ideas-editor): implement private idea draft CRUD

2 participants