Ir al contenido
DocuGraph

DocuGraph

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)»

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.

  • 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
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
)
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.1 Project Limit & Entitlement Verification

Sección titulada «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).

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 *;
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;
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.”
  • Unit Test: Test project limit check logic for Free vs Pro accounts.
  • Integration Test: Mock :docugraph-core workspace parser and verify node/edge DB insertions.