Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
eeee451
docs: add sirsoft-inquiry module design spec
RYANHEO86 May 20, 2026
f43ed65
docs: add sirsoft-inquiry backend foundation implementation plan
RYANHEO86 May 21, 2026
ad5d757
docs(plan): correct module patterns after BaseModuleServiceProvider r…
RYANHEO86 May 21, 2026
d0a6438
feat(inquiry): scaffold module skeleton
RYANHEO86 May 21, 2026
48ab7c7
feat(inquiry): add ServiceProvider skeleton + bootstrap test
RYANHEO86 May 21, 2026
f23bb7b
feat(inquiry): add module config (attachment/quote/permissions)
RYANHEO86 May 21, 2026
75551dd
feat(inquiry): add Status/Role/Event enums
RYANHEO86 May 21, 2026
f7cc078
feat(inquiry): add inquiries migration
RYANHEO86 May 21, 2026
1dc1bde
feat(inquiry): add inquiry_quotes migration
RYANHEO86 May 21, 2026
4719c26
feat(inquiry): add inquiry_quote_items migration
RYANHEO86 May 21, 2026
cdd7666
feat(inquiry): add inquiry_messages migration (with meta column for s…
RYANHEO86 May 21, 2026
fdd55da
feat(inquiry): add inquiry_attachments migration
RYANHEO86 May 21, 2026
2890e49
feat(inquiry): add Inquiry model with relationships and casts
RYANHEO86 May 21, 2026
cd1692e
feat(inquiry): add InquiryQuote + InquiryQuoteItem models
RYANHEO86 May 21, 2026
1eaaa72
feat(inquiry): add InquiryMessage + InquiryAttachment models
RYANHEO86 May 21, 2026
135dbf2
feat(inquiry): add domain exceptions
RYANHEO86 May 21, 2026
7bca962
feat(inquiry): add domain events
RYANHEO86 May 21, 2026
4614e5b
feat(inquiry): add system message lang files (ko/en)
RYANHEO86 May 21, 2026
4f5581d
feat(inquiry): add InquiryRepository
RYANHEO86 May 21, 2026
339f1e9
feat(inquiry): add InquiryQuoteRepository (issue/expire/accept)
RYANHEO86 May 21, 2026
b90e4ee
feat(inquiry): add InquiryMessageRepository (with appendSystem)
RYANHEO86 May 21, 2026
1d90da7
feat(inquiry): add InquiryAttachmentRepository
RYANHEO86 May 21, 2026
54b15d8
feat(inquiry): add StateMachine with issue_quote transition
RYANHEO86 May 21, 2026
28330f9
feat(inquiry): complete StateMachine transitions (revoke/reject/accep…
RYANHEO86 May 21, 2026
644af58
test(inquiry): cover illegal state transitions
RYANHEO86 May 21, 2026
3112d55
feat(inquiry): add InquiryAttachmentStorage service (mime/size valida…
RYANHEO86 May 21, 2026
28fca3b
feat(inquiry): add InquiryPolicy with permission matrix
RYANHEO86 May 21, 2026
131e306
docs(plan): add sirsoft-inquiry API + frontend implementation plan (P…
RYANHEO86 May 21, 2026
9536e37
feat(inquiry): add Message + Attachment API resources
RYANHEO86 May 21, 2026
e5c6233
feat(inquiry): add Quote + QuoteItem API resources (read-only)
RYANHEO86 May 21, 2026
f40c98f
feat(inquiry): add Inquiry API resource with abilities meta
RYANHEO86 May 21, 2026
1b8ba63
feat(inquiry): add Inquiry Store/Update form requests
RYANHEO86 May 21, 2026
5001fb9
feat(inquiry): add Message/Attachment form requests
RYANHEO86 May 21, 2026
299ea35
feat(inquiry): add InquiryController (index + show)
RYANHEO86 May 21, 2026
b4e68d7
feat(inquiry): add Inquiry store/update/cancel endpoints
RYANHEO86 May 21, 2026
fdcd554
feat(inquiry): register Inquiry API routes via module.php
RYANHEO86 May 21, 2026
4efa031
feat(inquiry): add InquiryMessageController (index/store) + routes
RYANHEO86 May 21, 2026
3a824be
feat(inquiry): add InquiryAttachmentController upload endpoints
RYANHEO86 May 21, 2026
eda8f0b
test(inquiry): cover attachment download permission
RYANHEO86 May 21, 2026
37ee878
test(inquiry): cover end-to-end client flow (create→msg→cancel)
RYANHEO86 May 21, 2026
0e694c2
feat(inquiry): add InquiryStatusBar composite
RYANHEO86 May 21, 2026
11dd606
feat(inquiry): add InquiryCard composite for list view
RYANHEO86 May 21, 2026
858dbbf
feat(inquiry): add InquiryMessageThread composite
RYANHEO86 May 21, 2026
6f3e993
feat(inquiry): add /inquiry index layout
RYANHEO86 May 21, 2026
76f117c
feat(inquiry): add /inquiry/new layout with submit flow
RYANHEO86 May 21, 2026
ce474bb
feat(inquiry): add cancel confirmation modal partial
RYANHEO86 May 21, 2026
08d6dc3
feat(inquiry): add /inquiry/{uuid} detail layout (status + summary + …
RYANHEO86 May 21, 2026
c5a3e01
feat(inquiry): register /inquiry routes (index/new/show)
RYANHEO86 May 21, 2026
5194e28
docs(plan): add sirsoft-inquiry quote + admin implementation plan (Pl…
RYANHEO86 May 21, 2026
29d98fe
feat(inquiry): add Admin\InquiryController (index/show) + admin routes
RYANHEO86 May 21, 2026
527a00c
feat(inquiry): add IssueQuoteRequest form request
RYANHEO86 May 21, 2026
85df8cf
feat(inquiry): add Admin\InquiryQuoteController issue + revoke
RYANHEO86 May 21, 2026
2880932
feat(inquiry): add User Quote accept/reject endpoints (stub bridge)
RYANHEO86 May 21, 2026
6794da5
feat(inquiry): wire InquiryPaymentBridge with ecommerce Order saved hook
RYANHEO86 May 21, 2026
4d7f793
feat(inquiry): add Admin action controller (paid_offline/complete/can…
RYANHEO86 May 21, 2026
d795e21
fix(inquiry): guard InquiryPaymentBridge::initiate against missing ec…
RYANHEO86 May 21, 2026
ce89434
feat(inquiry): add inquiry:expire-quotes command + daily schedule
RYANHEO86 May 21, 2026
efef449
feat(inquiry): add QuoteCard composite
RYANHEO86 May 21, 2026
c208080
feat(inquiry): activate QuoteCard accept/reject in /inquiry/{uuid}
RYANHEO86 May 21, 2026
aa1c65d
feat(inquiry): add admin_inquiry_index layout
RYANHEO86 May 21, 2026
e2f0023
feat(inquiry): add admin_inquiry_detail layout
RYANHEO86 May 21, 2026
e5bba66
feat(inquiry): add admin_inquiry_quote_form layout
RYANHEO86 May 21, 2026
d5909d1
feat(inquiry): add admin quote revoke modal
RYANHEO86 May 21, 2026
a746298
feat(inquiry): add admin mark-paid-offline modal
RYANHEO86 May 21, 2026
546444a
feat(inquiry): add admin inquiry complete modal
RYANHEO86 May 21, 2026
020ac03
feat(inquiry): add admin inquiry cancel modal
RYANHEO86 May 21, 2026
c8c26b6
feat(inquiry): register admin /admin/inquiry routes
RYANHEO86 May 21, 2026
750e3c9
docs(plan): add sirsoft-inquiry notifications + cleanup plan (Plan 4/…
RYANHEO86 May 22, 2026
af4cfb0
feat(inquiry): add InquiryNotification base + InquiryReceivedToOperators
RYANHEO86 May 22, 2026
4ebc1f0
feat(inquiry): add QuoteIssued + QuoteRevoked notifications
RYANHEO86 May 22, 2026
b298e17
feat(inquiry): add Payment/Completed/Canceled notifications
RYANHEO86 May 22, 2026
ff40db9
feat(inquiry): add NewMessageNotification
RYANHEO86 May 22, 2026
c90c1b5
feat(inquiry): add DispatchInquiryStatusNotifications listener
RYANHEO86 May 22, 2026
0a4c92f
feat(inquiry): add message + inquiry-created notification dispatch
RYANHEO86 May 22, 2026
9c7ccfb
feat(inquiry): register notification channels filter + event listeners
RYANHEO86 May 22, 2026
8253b71
test(inquiry): verify notifications fire on state transitions + messages
RYANHEO86 May 22, 2026
b730caf
feat(inquiry): add inquiry:cleanup-orphan-attachments command
RYANHEO86 May 22, 2026
7484a5a
feat(inquiry): add 제작의뢰 entry to user dropdown + mobile drawer
RYANHEO86 May 22, 2026
f358d61
fix(inquiry): use correct auth keys (auth_required + permissions:[])
RYANHEO86 May 22, 2026
7654cec
feat(inquiry): wire 제작의뢰 to gnb menus + apply aict subpage layout
RYANHEO86 May 22, 2026
83c15b6
feat(inquiry): add page-hero (eyebrow + title + lead + breadcrumb) to…
RYANHEO86 May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,633 changes: 2,633 additions & 0 deletions docs/superpowers/plans/2026-05-21-제작의뢰-api-frontend.md

Large diffs are not rendered by default.

2,986 changes: 2,986 additions & 0 deletions docs/superpowers/plans/2026-05-21-제작의뢰-backend-foundation.md

Large diffs are not rendered by default.

1,013 changes: 1,013 additions & 0 deletions docs/superpowers/plans/2026-05-22-제작의뢰-notifications.md

Large diffs are not rendered by default.

1,812 changes: 1,812 additions & 0 deletions docs/superpowers/plans/2026-05-22-제작의뢰-quote-admin.md

Large diffs are not rendered by default.

488 changes: 488 additions & 0 deletions docs/superpowers/specs/2026-05-20-제작의뢰-design.md

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions modules/_bundled/sirsoft-inquiry/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "modules/sirsoft-inquiry",
"description": "Inquiry module for Gnuboard7",
"type": "library",
"version": "1.0.0-alpha.1",
"license": "MIT",
"autoload": {
"psr-4": {
"Modules\\Sirsoft\\Inquiry\\": "src/",
"Modules\\Sirsoft\\Inquiry\\Database\\Seeders\\": "database/seeders/",
"Modules\\Sirsoft\\Inquiry\\Database\\Factories\\": "database/factories/"
}
},
"require": {
"php": "^8.2"
}
}
37 changes: 37 additions & 0 deletions modules/_bundled/sirsoft-inquiry/config/inquiry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

return [
'attachment' => [
'disk' => env('INQUIRY_ATTACHMENT_DISK', 'local'),
'max_size_inquiry' => env('INQUIRY_ATTACHMENT_MAX_INQUIRY', 50 * 1024 * 1024), // 50MB
'max_size_message' => env('INQUIRY_ATTACHMENT_MAX_MESSAGE', 20 * 1024 * 1024), // 20MB
'allowed_mimes' => [
'image/jpeg',
'image/png',
'image/webp',
'image/gif',
'application/pdf',
'application/zip',
'application/x-zip-compressed',
],
'orphan_cleanup_after_minutes' => 30,
],

'categories' => [
'web',
'design',
'maintenance',
'consulting',
'etc',
],

'quote' => [
'currency' => 'KRW',
'default_valid_days' => 14,
],

'permissions' => [
'manage' => 'inquiry.manage',
'notify' => 'inquiry.notify',
],
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::create('inquiries', function (Blueprint $table) {
$table->bigIncrements('id');
$table->uuid('uuid')->unique();
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
$table->string('title', 200);
$table->text('content');
$table->string('category', 50)->nullable();
$table->string('budget_range', 100)->nullable();
$table->date('desired_due_at')->nullable();
$table->string('status', 20)->default('received')->index();
$table->unsignedBigInteger('accepted_quote_id')->nullable();
$table->string('payment_id', 64)->nullable();
$table->json('extra_data')->nullable();
$table->timestamp('received_at')->useCurrent();
$table->timestamp('quoted_at')->nullable();
$table->timestamp('started_at')->nullable();
$table->timestamp('completed_at')->nullable();
$table->timestamp('canceled_at')->nullable();
$table->timestamps();

$table->index(['user_id', 'status']);
$table->index(['status', 'received_at']);
});
}

public function down(): void
{
Schema::dropIfExists('inquiries');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::create('inquiry_quotes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->foreignId('inquiry_id')->constrained('inquiries')->cascadeOnDelete();
$table->unsignedInteger('version');
$table->decimal('total_amount', 12, 0);
$table->decimal('tax_amount', 12, 0)->default(0);
$table->string('currency', 3)->default('KRW');
$table->date('valid_until')->nullable();
$table->text('note')->nullable();
$table->string('status', 20)->default('draft')->index();
$table->timestamp('issued_at')->nullable();
$table->timestamp('accepted_at')->nullable();
$table->timestamp('rejected_at')->nullable();
$table->timestamps();

$table->unique(['inquiry_id', 'version']);
});
}

public function down(): void
{
Schema::dropIfExists('inquiry_quotes');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::create('inquiry_quote_items', function (Blueprint $table) {
$table->bigIncrements('id');
$table->foreignId('quote_id')->constrained('inquiry_quotes')->cascadeOnDelete();
$table->unsignedInteger('position')->default(0);
$table->string('name', 200);
$table->text('description')->nullable();
$table->decimal('qty', 10, 2);
$table->decimal('unit_price', 12, 0);
$table->decimal('amount', 12, 0);
$table->timestamps();

$table->index(['quote_id', 'position']);
});
}

public function down(): void
{
Schema::dropIfExists('inquiry_quote_items');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::create('inquiry_messages', function (Blueprint $table) {
$table->bigIncrements('id');
$table->foreignId('inquiry_id')->constrained('inquiries')->cascadeOnDelete();
$table->foreignId('sender_user_id')->nullable()->constrained('users')->nullOnDelete();
$table->string('sender_role', 20);
$table->text('body')->nullable();
$table->json('meta')->nullable();
$table->timestamp('read_at')->nullable();
$table->timestamps();

$table->index(['inquiry_id', 'created_at']);
});
}

public function down(): void
{
Schema::dropIfExists('inquiry_messages');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::create('inquiry_attachments', function (Blueprint $table) {
$table->bigIncrements('id');
$table->foreignId('inquiry_id')->constrained('inquiries')->cascadeOnDelete();
$table->foreignId('message_id')->nullable()->constrained('inquiry_messages')->cascadeOnDelete();
$table->foreignId('uploader_user_id')->constrained('users')->cascadeOnDelete();
$table->string('disk', 20);
$table->string('path');
$table->string('original_name', 255);
$table->string('mime', 100);
$table->unsignedBigInteger('size');
$table->timestamps();

$table->index(['inquiry_id', 'message_id']);
});
}

public function down(): void
{
Schema::dropIfExists('inquiry_attachments');
}
};
19 changes: 19 additions & 0 deletions modules/_bundled/sirsoft-inquiry/module.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"identifier": "sirsoft-inquiry",
"vendor": "sirsoft",
"name": {
"ko": "제작의뢰",
"en": "Inquiry"
},
"version": "1.0.0-alpha.1",
"license": "MIT",
"description": {
"ko": "제작의뢰 라이프사이클(접수·견적·진행·완료) 관리 모듈",
"en": "Inquiry lifecycle module (received / quoted / in_progress / completed)"
},
"g7_version": ">=7.0.0-beta.5",
"dependencies": {
"modules": {},
"plugins": {}
}
}
18 changes: 18 additions & 0 deletions modules/_bundled/sirsoft-inquiry/module.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Modules\Sirsoft\Inquiry;

use App\Extension\AbstractModule;

class Module extends AbstractModule
{
// Minimal scaffold for inquiry module.
// Permissions, event listeners, and seeders will be added in subsequent tasks.

public function getRoutes(): array
{
return [
'api' => $this->getModulePath() . '/src/routes/api.php',
];
}
}
Loading