Backend Spec: Project Creation & Frontmatter Workspace Scanning (project.create)
Estado de fase (MASTER-00): POST_MVP — documento de catálogo de producto sujeto a validación; no es alcance aprobado de Gate 0 / PoC / MVP. Gobernanza: MASTER-00.
Backend Spec: Project Creation & Frontmatter Workspace Scanning (project.create)
Sección titulada «Backend Spec: Project Creation & Frontmatter Workspace Scanning (project.create)»1. Overview & Objectives
Sección titulada «1. Overview & Objectives»This specification defines the server-side logic for registering a new documentation project (createProject) in :docugraph-backend. It receives HTTP POST /api/v1/projects, enforces subscription tier limits (max 3 active projects for Free tier), initializes a project entry in PostgreSQL projects with status INITIALIZING, delegates Markdown frontmatter scanning to :docugraph-core, and updates project metadata upon completion.
2. API Endpoint Signature & Traceability
Sección titulada «2. API Endpoint Signature & Traceability»- HTTP Method & Path:
POST /api/v1/projects - operationId:
createProject - Upstream Requirements:
US-02,IX-02,SCHEMA-01 - Primary Service Class:
ProjectService.kt - Ktor Route Handler:
ProjectRoutes.kt
3. Data Models & Kotlin Data Classes
Sección titulada «3. Data Models & Kotlin Data Classes»package io.docugraph.backend.models.project
import kotlinx.serialization.Serializable
@Serializabledata class CreateProjectRequest( val name: String, val description: String? = null, val workspacePath: String, val gitRemoteUrl: String? = null, val gitDefaultBranch: String = "main", val schemaConfig: Map<String, String> = emptyMap())
@Serializabledata class ProjectResponse( val id: String, val ownerId: String, val name: String, val description: String?, val workspacePath: String, val gitRemoteUrl: String?, val status: String, // "INITIALIZING" | "ACTIVE" | "INDEXING_FAILED" val nodeCount: Int, val edgeCount: Int, val lastIndexedAt: String?, val createdAt: String, val updatedAt: String)4. Sequence & Control Flow
Sección titulada «4. Sequence & Control Flow»Client (FE-02) Ktor ProjectRoute ProjectService Core Engine (:docugraph-core) PostgreSQL DB | | | | | |-- POST /projects ----->| | | | | (CreateProjectReq) |-- checkEntitlement ->|--------------------------------------------->| SELECT COUNT | | |<- sub status & count ------------------------| | | | | | | | |-- INSERT project (INIT)--------------------->| INSERT projects | | | | | | | |-- scanWorkspace(path) -->| | | | | |-- parse YAML frontmatters | | | |-- construct DAG | | | |<- ParsedGraph (nodes/edges)------------------| | | | | | | | |-- batch insert nodes & edges --------------->| INSERT nodes/edges | | |-- UPDATE status = ACTIVE ------------------->| UPDATE projects |<- 201 Created ---------|<- ProjectResponse ---| | |5. Database Interaction & SQL Queries
Sección titulada «5. Database Interaction & SQL Queries»5.1 Project Limit & Entitlement Verification
Sección titulada «5.1 Project Limit & Entitlement Verification»SELECT s.entitlement_id, COUNT(p.id) AS active_project_countFROM subscriptions sLEFT JOIN projects p ON p.owner_id = s.user_idWHERE s.user_id = :userIdGROUP BY s.entitlement_id;Business Rule: If entitlement_id == 'free' and active_project_count >= 3, reject request with 403 Forbidden (PROJECT_LIMIT_EXCEEDED).
5.2 Insert Project Record
Sección titulada «5.2 Insert Project Record»INSERT INTO projects ( owner_id, name, description, workspace_path, git_remote_url, git_default_branch, schema_config, node_count, edge_count, last_indexed_at) VALUES ( :ownerId, :name, :description, :workspacePath, :gitRemoteUrl, :gitDefaultBranch, :schemaConfig::jsonb, 0, 0, NULL)RETURNING *;5.3 Batch Insert Parsed Nodes and Edges
Sección titulada «5.3 Batch Insert Parsed Nodes and Edges»INSERT INTO nodes ( project_id, atomic_id, title, document_type, status, relative_file_path, file_checksum_sha256, frontmatter_json, tags) VALUES ( :projectId, :atomicId, :title, :docType, :status, :relPath, :checksum, :frontmatterJson::jsonb, :tags)ON CONFLICT (project_id, atomic_id) DO UPDATE SET title = EXCLUDED.title, document_type = EXCLUDED.document_type, status = EXCLUDED.status, relative_file_path = EXCLUDED.relative_file_path, file_checksum_sha256 = EXCLUDED.file_checksum_sha256, frontmatter_json = EXCLUDED.frontmatter_json, tags = EXCLUDED.tags, updated_at = CURRENT_TIMESTAMP;INSERT INTO node_edges ( project_id, source_node_id, target_node_id, relationship_type) VALUES ( :projectId, :sourceNodeId, :targetNodeId, :relationshipType)ON CONFLICT (source_node_id, target_node_id, relationship_type) DO NOTHING;6. Error Handling & HTTP Status Codes
Sección titulada «6. Error Handling & HTTP Status Codes»| Error Condition | HTTP Code | Internal Code | Response Message |
|---|---|---|---|
| Invalid workspace directory path | 400 Bad Request | INVALID_WORKSPACE_PATH |
“Workspace path does not exist or is unreadable.” |
| Free tier project limit (3) reached | 403 Forbidden | PROJECT_LIMIT_EXCEEDED |
“Free tier limited to 3 projects. Upgrade to Pro Tier.” |
| Duplicate project name or path for owner | 409 Conflict | PROJECT_ALREADY_EXISTS |
“Project already registered for this path.” |
| Parser engine crash | 500 Server Error | INDEXING_FAILED |
“Failed to parse Markdown workspace files.” |
7. Verification & Test Plan
Sección titulada «7. Verification & Test Plan»- Unit Test: Test project limit check logic for Free vs Pro accounts.
- Integration Test: Mock
:docugraph-coreworkspace parser and verify node/edge DB insertions.