Files
sam-docs/plans/document-management-system-plan.md
2026-01-28 21:29:11 +09:00

30 KiB

문서 관리 시스템 개발 계획

작성일: 2025-01-28 목적: 문서 템플릿 기반 실제 문서 작성/결재/관리 시스템 상태: 📋 계획 수립


📍 현재 진행 상태

항목 내용
마지막 완료 작업 Phase 1.8 - Route 등록 및 Swagger 문서
다음 작업 Phase 2 - MNG 관리자 패널 구현
진행률 6/12 (50%)
보류 항목 결재 워크플로우 (submit/approve/reject/cancel) - 기존 시스템 연동 필요
마지막 업데이트 2026-01-28

0. 빠른 시작 가이드

0.1 전제 조건

# Docker 서비스 실행 확인
docker ps | grep sam

# 예상 결과: sam-api-1, sam-mng-1, sam-mysql-1, sam-nginx-1 실행 중

0.2 프로젝트 경로

프로젝트 경로 설명
API /Users/kent/Works/@KD_SAM/SAM/api Laravel 12 REST API
MNG /Users/kent/Works/@KD_SAM/SAM/mng Laravel 12 + Blade 관리자
React /Users/kent/Works/@KD_SAM/SAM/react Next.js 15 프론트엔드

0.3 작업 시작 명령어

# 1. API 마이그레이션 상태 확인
docker exec sam-api-1 php artisan migrate:status

# 2. 새 마이그레이션 생성
docker exec sam-api-1 php artisan make:migration create_documents_table

# 3. 마이그레이션 실행
docker exec sam-api-1 php artisan migrate

# 4. 모델 생성
docker exec sam-api-1 php artisan make:model Document

# 5. 코드 포맷팅
docker exec sam-api-1 ./vendor/bin/pint

0.4 작업 순서 요약

Phase 1 (API)
├── 1.1 마이그레이션 파일 생성 → 컨펌 필요
├── 1.2 마이그레이션 실행
├── 1.3 모델 생성 (Document, DocumentApproval, DocumentData)
├── 1.4 Service 생성 (DocumentService)
├── 1.5 Controller 생성 (DocumentController)
└── 1.6 Swagger 문서

Phase 2 (MNG)
├── 2.1 모델 복사/수정
├── 2.2 문서 목록 화면
├── 2.3 문서 상세/편집 화면
└── 2.4 문서 생성 화면

Phase 3 (React)
├── 3.1 문서 작성 컴포넌트
├── 3.2 결재선 지정 UI
└── 3.3 수입검사 연동

1. 개요

1.1 배경

현재 SAM 시스템에는 문서 템플릿 관리 기능이 존재하나, 실제 문서를 작성하고 관리하는 기능이 없음.

현재 상태:

  • MNG: 문서 템플릿 관리 (/document-templates)
  • 실제 문서 작성/관리 기능 없음
  • 결재 시스템과 연동 없음

목표:

  • 템플릿 기반 동적 문서 생성
  • 결재 시스템 연동
  • 수입검사/입고등록에서 실사용

1.2 시스템 구조

┌─────────────────────────────────────────────────────────────────┐
│                        문서 관리 시스템                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  [MNG 관리자]                    [React 사용자]                   │
│  ┌──────────────┐               ┌──────────────┐                │
│  │ 템플릿 관리   │               │ 문서 작성    │                 │
│  │ 문서 관리    │               │ 결재 처리    │                 │
│  └──────────────┘               └──────────────┘                │
│         │                              │                        │
│         └──────────────┬───────────────┘                        │
│                        ▼                                        │
│                   [API Server]                                  │
│                        │                                        │
│                        ▼                                        │
│                   [Database]                                    │
│  documents, document_approvals, document_data                   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

1.3 변경 승인 정책

분류 예시 승인
즉시 가능 필드 추가, 문서 수정 불필요
⚠️ 컨펌 필요 마이그레이션, 새 API 필수
🔴 금지 기존 테이블 변경 별도 협의

2. 대상 범위

2.1 Phase 1: Database & API

# 작업 항목 상태 파일 경로
1.1 마이그레이션 생성 api/database/migrations/2026_01_28_200000_create_documents_table.php
1.2 Document 모델 api/app/Models/Documents/Document.php
1.3 DocumentApproval 모델 api/app/Models/Documents/DocumentApproval.php
1.4 DocumentData 모델 api/app/Models/Documents/DocumentData.php
1.5 DocumentService api/app/Services/DocumentService.php
1.6 DocumentController api/app/Http/Controllers/Api/V1/DocumentController.php
1.7 FormRequest api/app/Http/Requests/Document/
1.8 Swagger 문서 api/app/Swagger/v1/DocumentApi.php

2.2 Phase 2: MNG 관리 화면

# 작업 항목 상태 파일 경로
2.1 Document 모델 mng/app/Models/Document.php
2.2 DocumentController mng/app/Http/Controllers/DocumentController.php
2.3 문서 목록 뷰 mng/resources/views/documents/index.blade.php
2.4 문서 상세 뷰 mng/resources/views/documents/show.blade.php
2.5 문서 생성 뷰 mng/resources/views/documents/create.blade.php
2.6 API Controller mng/app/Http/Controllers/Api/Admin/DocumentApiController.php

2.3 Phase 3: React 연동

# 작업 항목 상태 파일 경로
3.1 문서 작성 컴포넌트 react/src/components/document-system/DocumentForm/
3.2 API actions react/src/components/document-system/actions.ts
3.3 수입검사 연동 react/src/components/material/ReceivingManagement/

3. 상세 설계

3.1 Database Schema (마이그레이션 파일)

<?php
// api/database/migrations/2026_01_29_000000_create_documents_table.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('documents', function (Blueprint $table) {
            $table->id();
            $table->foreignId('tenant_id')->constrained()->cascadeOnDelete();
            $table->foreignId('template_id')->constrained('document_templates');

            // 문서 정보
            $table->string('document_no', 50)->comment('문서번호');
            $table->string('title', 255)->comment('문서 제목');
            $table->enum('status', ['DRAFT', 'PENDING', 'APPROVED', 'REJECTED', 'CANCELLED'])
                  ->default('DRAFT')->comment('상태');

            // 연결 정보 (다형성)
            $table->string('linkable_type', 100)->nullable()->comment('연결 타입');
            $table->unsignedBigInteger('linkable_id')->nullable()->comment('연결 ID');

            // 메타 정보
            $table->foreignId('created_by')->constrained('users');
            $table->timestamp('submitted_at')->nullable()->comment('결재 요청일');
            $table->timestamp('completed_at')->nullable()->comment('결재 완료일');

            $table->timestamps();
            $table->softDeletes();

            $table->index(['tenant_id', 'status']);
            $table->index('document_no');
            $table->index(['linkable_type', 'linkable_id']);
        });

        // 문서 결재
        Schema::create('document_approvals', function (Blueprint $table) {
            $table->id();
            $table->foreignId('document_id')->constrained()->cascadeOnDelete();
            $table->foreignId('user_id')->constrained();

            $table->unsignedTinyInteger('step')->default(1)->comment('결재 순서');
            $table->string('role', 50)->comment('역할 (작성/검토/승인)');
            $table->enum('status', ['PENDING', 'APPROVED', 'REJECTED'])
                  ->default('PENDING')->comment('상태');

            $table->text('comment')->nullable()->comment('결재 의견');
            $table->timestamp('acted_at')->nullable()->comment('결재 처리일');

            $table->timestamps();

            $table->index(['document_id', 'step']);
        });

        // 문서 데이터
        Schema::create('document_data', function (Blueprint $table) {
            $table->id();
            $table->foreignId('document_id')->constrained()->cascadeOnDelete();

            $table->unsignedBigInteger('section_id')->nullable()->comment('섹션 ID');
            $table->unsignedBigInteger('column_id')->nullable()->comment('컬럼 ID');
            $table->unsignedSmallInteger('row_index')->default(0)->comment('행 인덱스');

            $table->string('field_key', 100)->comment('필드 키');
            $table->text('field_value')->nullable()->comment('값');

            $table->timestamps();

            $table->index(['document_id', 'section_id']);
        });

        // 문서 첨부파일
        Schema::create('document_attachments', function (Blueprint $table) {
            $table->id();
            $table->foreignId('document_id')->constrained()->cascadeOnDelete();
            $table->foreignId('file_id')->constrained('files');

            $table->string('attachment_type', 50)->default('general')->comment('유형');
            $table->string('description', 255)->nullable();

            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('document_attachments');
        Schema::dropIfExists('document_data');
        Schema::dropIfExists('document_approvals');
        Schema::dropIfExists('documents');
    }
};

3.2 Model 코드 템플릿

<?php
// api/app/Models/Documents/Document.php

namespace App\Models\Documents;

use App\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletes;

class Document extends Model
{
    use BelongsToTenant, SoftDeletes;

    protected $fillable = [
        'tenant_id',
        'template_id',
        'document_no',
        'title',
        'status',
        'linkable_type',
        'linkable_id',
        'created_by',
        'submitted_at',
        'completed_at',
    ];

    protected $casts = [
        'submitted_at' => 'datetime',
        'completed_at' => 'datetime',
    ];

    // === 상태 상수 ===
    public const STATUS_DRAFT = 'DRAFT';
    public const STATUS_PENDING = 'PENDING';
    public const STATUS_APPROVED = 'APPROVED';
    public const STATUS_REJECTED = 'REJECTED';
    public const STATUS_CANCELLED = 'CANCELLED';

    // === 관계 ===
    public function template(): BelongsTo
    {
        return $this->belongsTo(\App\Models\DocumentTemplate::class, 'template_id');
    }

    public function approvals(): HasMany
    {
        return $this->hasMany(DocumentApproval::class)->orderBy('step');
    }

    public function data(): HasMany
    {
        return $this->hasMany(DocumentData::class);
    }

    public function attachments(): HasMany
    {
        return $this->hasMany(DocumentAttachment::class);
    }

    public function linkable(): MorphTo
    {
        return $this->morphTo();
    }

    public function creator(): BelongsTo
    {
        return $this->belongsTo(\App\Models\User::class, 'created_by');
    }

    // === 스코프 ===
    public function scopeStatus($query, string $status)
    {
        return $query->where('status', $status);
    }

    // === 헬퍼 ===
    public function canEdit(): bool
    {
        return $this->status === self::STATUS_DRAFT;
    }

    public function canSubmit(): bool
    {
        return $this->status === self::STATUS_DRAFT;
    }
}
<?php
// api/app/Models/Documents/DocumentApproval.php

namespace App\Models\Documents;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class DocumentApproval extends Model
{
    protected $fillable = [
        'document_id',
        'user_id',
        'step',
        'role',
        'status',
        'comment',
        'acted_at',
    ];

    protected $casts = [
        'step' => 'integer',
        'acted_at' => 'datetime',
    ];

    public const STATUS_PENDING = 'PENDING';
    public const STATUS_APPROVED = 'APPROVED';
    public const STATUS_REJECTED = 'REJECTED';

    public function document(): BelongsTo
    {
        return $this->belongsTo(Document::class);
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(\App\Models\User::class);
    }
}
<?php
// api/app/Models/Documents/DocumentData.php

namespace App\Models\Documents;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class DocumentData extends Model
{
    protected $table = 'document_data';

    protected $fillable = [
        'document_id',
        'section_id',
        'column_id',
        'row_index',
        'field_key',
        'field_value',
    ];

    protected $casts = [
        'row_index' => 'integer',
    ];

    public function document(): BelongsTo
    {
        return $this->belongsTo(Document::class);
    }
}

3.3 Service 코드 템플릿

<?php
// api/app/Services/DocumentService.php

namespace App\Services;

use App\Models\Documents\Document;
use App\Models\Documents\DocumentApproval;
use App\Models\Documents\DocumentData;
use Illuminate\Pagination\LengthAwarePaginator;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class DocumentService extends Service
{
    /**
     * 문서 목록 조회
     */
    public function list(array $params): LengthAwarePaginator
    {
        $query = Document::query()
            ->where('tenant_id', $this->tenantId())
            ->with(['template:id,name,category', 'creator:id,name']);

        // 필터
        if (!empty($params['status'])) {
            $query->where('status', $params['status']);
        }
        if (!empty($params['template_id'])) {
            $query->where('template_id', $params['template_id']);
        }
        if (!empty($params['search'])) {
            $search = $params['search'];
            $query->where(function ($q) use ($search) {
                $q->where('document_no', 'like', "%{$search}%")
                  ->orWhere('title', 'like', "%{$search}%");
            });
        }

        return $query->orderByDesc('id')
            ->paginate($params['per_page'] ?? 20);
    }

    /**
     * 문서 상세 조회
     */
    public function show(int $id): Document
    {
        $document = Document::with([
            'template.approvalLines',
            'template.sections.items',
            'template.columns',
            'approvals.user:id,name',
            'data',
            'creator:id,name',
        ])->find($id);

        if (!$document || $document->tenant_id !== $this->tenantId()) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        return $document;
    }

    /**
     * 문서 생성
     */
    public function create(array $data): Document
    {
        $document = Document::create([
            'tenant_id' => $this->tenantId(),
            'template_id' => $data['template_id'],
            'document_no' => $this->generateDocumentNo($data['template_id']),
            'title' => $data['title'],
            'status' => Document::STATUS_DRAFT,
            'linkable_type' => $data['linkable_type'] ?? null,
            'linkable_id' => $data['linkable_id'] ?? null,
            'created_by' => $this->apiUserId(),
        ]);

        // 결재선 생성
        if (!empty($data['approvers'])) {
            foreach ($data['approvers'] as $step => $approver) {
                DocumentApproval::create([
                    'document_id' => $document->id,
                    'user_id' => $approver['user_id'],
                    'step' => $step + 1,
                    'role' => $approver['role'],
                    'status' => DocumentApproval::STATUS_PENDING,
                ]);
            }
        }

        // 데이터 저장
        if (!empty($data['data'])) {
            foreach ($data['data'] as $item) {
                DocumentData::create([
                    'document_id' => $document->id,
                    'section_id' => $item['section_id'] ?? null,
                    'column_id' => $item['column_id'] ?? null,
                    'row_index' => $item['row_index'] ?? 0,
                    'field_key' => $item['field_key'],
                    'field_value' => $item['field_value'],
                ]);
            }
        }

        return $document->fresh(['approvals', 'data']);
    }

    /**
     * 결재 요청 (DRAFT → PENDING)
     */
    public function submit(int $id): Document
    {
        $document = $this->show($id);

        if (!$document->canSubmit()) {
            throw new BadRequestHttpException(__('error.invalid_status'));
        }

        $document->update([
            'status' => Document::STATUS_PENDING,
            'submitted_at' => now(),
        ]);

        return $document->fresh();
    }

    /**
     * 결재 승인
     */
    public function approve(int $id, ?string $comment = null): Document
    {
        $document = $this->show($id);
        $userId = $this->apiUserId();

        // 현재 사용자의 결재 단계 찾기
        $approval = $document->approvals
            ->where('user_id', $userId)
            ->where('status', DocumentApproval::STATUS_PENDING)
            ->first();

        if (!$approval) {
            throw new BadRequestHttpException(__('error.not_your_turn'));
        }

        $approval->update([
            'status' => DocumentApproval::STATUS_APPROVED,
            'comment' => $comment,
            'acted_at' => now(),
        ]);

        // 모든 결재 완료 확인
        $allApproved = $document->approvals()
            ->where('status', '!=', DocumentApproval::STATUS_APPROVED)
            ->doesntExist();

        if ($allApproved) {
            $document->update([
                'status' => Document::STATUS_APPROVED,
                'completed_at' => now(),
            ]);
        }

        return $document->fresh(['approvals']);
    }

    /**
     * 결재 반려
     */
    public function reject(int $id, string $comment): Document
    {
        $document = $this->show($id);
        $userId = $this->apiUserId();

        $approval = $document->approvals
            ->where('user_id', $userId)
            ->where('status', DocumentApproval::STATUS_PENDING)
            ->first();

        if (!$approval) {
            throw new BadRequestHttpException(__('error.not_your_turn'));
        }

        $approval->update([
            'status' => DocumentApproval::STATUS_REJECTED,
            'comment' => $comment,
            'acted_at' => now(),
        ]);

        $document->update([
            'status' => Document::STATUS_REJECTED,
            'completed_at' => now(),
        ]);

        return $document->fresh(['approvals']);
    }

    /**
     * 문서번호 생성
     */
    private function generateDocumentNo(int $templateId): string
    {
        $prefix = 'DOC';
        $date = now()->format('Ymd');
        $count = Document::where('tenant_id', $this->tenantId())
            ->whereDate('created_at', today())
            ->count() + 1;

        return sprintf('%s-%s-%04d', $prefix, $date, $count);
    }
}

3.4 Controller 코드 템플릿

<?php
// api/app/Http/Controllers/Api/V1/DocumentController.php

namespace App\Http\Controllers\Api\V1;

use App\Helpers\ApiResponse;
use App\Http\Controllers\Controller;
use App\Http\Requests\Document\CreateDocumentRequest;
use App\Http\Requests\Document\ApproveDocumentRequest;
use App\Http\Requests\Document\RejectDocumentRequest;
use App\Services\DocumentService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class DocumentController extends Controller
{
    public function __construct(
        private readonly DocumentService $service
    ) {}

    public function index(Request $request): JsonResponse
    {
        return ApiResponse::handle(
            fn () => $this->service->list($request->all()),
            __('message.fetched')
        );
    }

    public function show(int $id): JsonResponse
    {
        return ApiResponse::handle(
            fn () => $this->service->show($id),
            __('message.fetched')
        );
    }

    public function store(CreateDocumentRequest $request): JsonResponse
    {
        return ApiResponse::handle(
            fn () => $this->service->create($request->validated()),
            __('message.created')
        );
    }

    public function submit(int $id): JsonResponse
    {
        return ApiResponse::handle(
            fn () => $this->service->submit($id),
            __('message.document.submitted')
        );
    }

    public function approve(int $id, ApproveDocumentRequest $request): JsonResponse
    {
        return ApiResponse::handle(
            fn () => $this->service->approve($id, $request->comment),
            __('message.document.approved')
        );
    }

    public function reject(int $id, RejectDocumentRequest $request): JsonResponse
    {
        return ApiResponse::handle(
            fn () => $this->service->reject($id, $request->comment),
            __('message.document.rejected')
        );
    }
}

3.5 API Routes

// api/routes/api.php 에 추가

Route::prefix('v1')->middleware(['auth.apikey'])->group(function () {
    // ... 기존 라우트 ...

    // 문서 관리
    Route::prefix('documents')->middleware(['auth:sanctum'])->group(function () {
        Route::get('/', [DocumentController::class, 'index']);
        Route::post('/', [DocumentController::class, 'store']);
        Route::get('/{id}', [DocumentController::class, 'show']);
        Route::put('/{id}', [DocumentController::class, 'update']);
        Route::delete('/{id}', [DocumentController::class, 'destroy']);

        // 결재
        Route::post('/{id}/submit', [DocumentController::class, 'submit']);
        Route::post('/{id}/approve', [DocumentController::class, 'approve']);
        Route::post('/{id}/reject', [DocumentController::class, 'reject']);
        Route::post('/{id}/cancel', [DocumentController::class, 'cancel']);
    });
});

3.6 문서 상태 흐름

┌──────────────────────────────────────────────────────────────┐
│                                                               │
│   DRAFT ──submit──> PENDING ──approve──> APPROVED            │
│     │                  │                                      │
│     │                  │──reject──> REJECTED                  │
│     │                  │                   │                  │
│     │                  │──cancel──> CANCELLED                 │
│     │                              │                          │
│     └──────────────────<──edit─────┘ (반려 시 수정 후 재요청)  │
│                                                               │
└──────────────────────────────────────────────────────────────┘

4. 기존 코드 참조 (인라인)

4.1 기존 템플릿 테이블 구조

document_templates (기존)
├── id, tenant_id, name, category, title
├── company_name, company_address, company_contact
├── footer_remark_label, footer_judgement_label
├── footer_judgement_options (JSON)
└── is_active, timestamps, soft_deletes

document_template_approval_lines (기존)
├── id, template_id, name, dept, role, sort_order
└── timestamps

document_template_sections (기존)
├── id, template_id, title, image_path, sort_order
└── timestamps

document_template_section_items (기존)
├── id, section_id, category, item, standard
├── method, frequency, regulation, sort_order
└── timestamps

document_template_columns (기존)
├── id, template_id, label, width, column_type
├── group_name, sub_labels (JSON), sort_order
└── timestamps

4.2 API Service 기본 클래스

// api/app/Services/Service.php (기존)
abstract class Service
{
    protected function tenantIdOrNull(): ?int;  // 테넌트 ID (없으면 null)
    protected function tenantId(): int;         // 테넌트 ID (없으면 400 예외)
    protected function apiUserId(): int;        // 사용자 ID (없으면 401 예외)
}

4.3 API Response 헬퍼

// api/app/Helpers/ApiResponse.php (기존)
use App\Helpers\ApiResponse;

// 성공 응답
ApiResponse::success($data, $message, $debug, $statusCode);

// 에러 응답
ApiResponse::error($message, $code, $error);

// 컨트롤러에서 사용 (권장)
ApiResponse::handle(fn () => $this->service->method(), __('message.xxx'));

4.4 React 결재선 컴포넌트 위치

react/src/components/approval/DocumentCreate/ApprovalLineSection.tsx
- 직원 목록에서 결재자 선택
- getEmployees() 호출로 직원 목록 조회
- ApprovalPerson[] 형태로 결재선 관리

5. 작업 절차

Step 1: 마이그레이션 생성 (⚠️ 컨펌 필요)

# 1. 마이그레이션 파일 생성
docker exec sam-api-1 php artisan make:migration create_documents_table

# 2. 위 3.1 스키마 코드 붙여넣기

# 3. 마이그레이션 실행
docker exec sam-api-1 php artisan migrate

Step 2: 모델 생성

# Documents 폴더 생성 후 모델 파일 생성
mkdir -p api/app/Models/Documents

# 위 3.2 모델 코드 각각 생성

Step 3: Service & Controller

# Service 생성
# api/app/Services/DocumentService.php

# Controller 생성
# api/app/Http/Controllers/Api/V1/DocumentController.php

# Routes 추가
# api/routes/api.php

Step 4: MNG 화면

# mng/app/Models/Document.php
# mng/app/Http/Controllers/DocumentController.php
# mng/resources/views/documents/*.blade.php

Step 5: React 연동

# react/src/components/document-system/DocumentForm/
# react/src/components/document-system/actions.ts

6. 컨펌 대기 목록

# 항목 변경 내용 영향 범위 상태
1 DB 스키마 4개 테이블 신규 생성 api/database 대기

7. 변경 이력

날짜 항목 변경 내용 파일 승인
2025-01-28 - 계획 문서 작성 - -
2025-01-28 - 자기완결성 보완 - -
2026-01-28 Phase 1.1 마이그레이션 파일 생성 및 실행 2026_01_28_200000_create_documents_table.php
2026-01-28 Phase 1.2 모델 생성 (Document, DocumentApproval, DocumentData, DocumentAttachment) api/app/Models/Documents/

8. 검증 결과

작업 완료 후 이 섹션에 검증 결과 추가

8.1 테스트 케이스

시나리오 예상 결과 실제 결과 상태
마이그레이션 실행 4개 테이블 생성 4개 테이블 생성 (524ms)
문서 생성 API 201 Created -
결재 요청 DRAFT → PENDING -
결재 승인 PENDING → APPROVED -
결재 반려 PENDING → REJECTED -

9. 자기완결성 점검 결과

9.1 체크리스트 검증

# 검증 항목 상태 비고
1 작업 목적이 명확한가? 1.1 배경 섹션
2 성공 기준이 정의되어 있는가? 8.1 테스트 케이스
3 작업 범위가 구체적인가? 2. 대상 범위 (파일 경로 포함)
4 의존성이 명시되어 있는가? 0.1 전제 조건
5 참고 파일 경로가 정확한가? 4. 기존 코드 참조
6 단계별 절차가 실행 가능한가? 5. 작업 절차
7 검증 방법이 명시되어 있는가? 8. 검증 결과
8 모호한 표현이 없는가? 코드 템플릿 제공

9.2 새 세션 시뮬레이션 테스트

질문 답변 가능 참조 섹션
Q1. 이 작업의 목적은 무엇인가? 1.1 배경
Q2. 어디서부터 시작해야 하는가? 0.4 작업 순서, 5. 작업 절차
Q3. 어떤 파일을 수정해야 하는가? 2. 대상 범위
Q4. 작업 완료 확인 방법은? 8. 검증 결과
Q5. 막혔을 때 참고 문서는? 4. 기존 코드 참조

결과: 5/5 통과 → 자기완결성 확보


이 문서는 /plan 스킬로 생성되었습니다.