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)
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
- 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
package io.docugraph.backend.models.project
import kotlinx.serialization.Serializable
@Serializable
data 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()
)
@Serializable
data 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
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
5.1 Project Limit & Entitlement Verification
SELECT
s.entitlement_id,
COUNT(p.id) AS active_project_count
FROM subscriptions s
LEFT JOIN projects p ON p.owner_id = s.user_id
WHERE s.user_id = :userId
GROUP 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
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
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
| 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
- Unit Test: Test project limit check logic for Free vs Pro accounts.
- Integration Test: Mock
:docugraph-coreworkspace parser and verify node/edge DB insertions.