Internal Documentation internal
TalkIDE internal documentation

Create a new project through a chat-like conversational onboarding driven by Pseudo-Mara (a UI simulation, no LLM call). The wizard collects name, description, URL slug, accent color, and tech stack one bubble at a time, then atomically creates the project together with its first conversation. Requires a valid JWT access token. The project is created in DRAFT status and belongs to the authenticated user’s tenant.

Conversational onboarding (UX overview)

The user lands on the New Project screen and sees a chat-like timeline rather than a form. Each step is a Pseudo-Mara bubble followed by an inline InteractivePrompt component (input / textarea / chips). Pseudo-Mara is purely a frontend simulation — there is no backend or LLM call until the final submit.

Step-by-step sequence:

  1. Greeting bubblei18n: createProject.greeting → e.g. "Ahoj {firstName}, dej mi pár základních informací." ({firstName} resolved from the authenticated user’s profile).
  2. Name — inline InteractivePrompt of type input, mandatory (max 100 chars). The Next button stays disabled until the user types a non-blank value.
  3. Description — inline InteractivePrompt of type textarea, optional (max 500 chars). Counter shown; over-limit blocks Next.
  4. URL slug — inline InteractivePrompt of type input with a fixed suffix .talkide.app rendered next to the field. The user only types the slug part. The FE auto-prefills the slug from the project name (kebab-cased), but the user can override it. As the user types, the FE debounces input by 400 ms and calls GET /api/v1/projects/check-url?url=<slug>.talkide.app. Until the slug is valid AND available, Next stays disabled. An inline status chip shows checking…, available, taken, or invalid format.
  5. Accent — inline InteractivePrompt of type chips with the 6 oklch presets of the design system (the legacy custom color picker has been removed). Mandatory. Default selection: the first preset.
  6. Tech-stack offer — bubble: "Použijeme technologie se kterými máme dlouhodobě nejlepší výsledky?" followed by 2 chips:
    • ANO (doporučeno) — the FE submits without sending any tech-stack fields; the BE fills in defaults (Kotlin / Spring Boot / TypeScript / Vue.js).
    • Vyberu si svůj tech stack — opens 4 additional inline chip prompts, in order:
      1. Backend languageKotlin (doporučeno) / Java / TypeScript / Python
      2. Backend frameworkSpring Boot (doporučeno) / Quarkus / NestJS / Django
      3. Frontend languageTypeScript (doporučeno) / JavaScript
      4. Frontend frameworkVue.js (doporučeno) / React / Svelte

After the tech-stack step the FE submits POST /api/v1/projects. The BE atomically:

  • creates the project (status = DRAFT),
  • immediately starts the first conversation via StartConversationUseCase (no user message yet — see UC-04002, “auto-start variant”),
  • returns the new projectId and conversationId in the same response.

The FE then routes to /workspace/:projectId, loads the conversation, and lets the real Mara (LLM, streamed via SSE) deliver an opening message without any user input. Mara uses {{project.description}} from her rendered context as the situational anchor; she does not greet the user (Pseudo-Mara already did) and asks a short, focused question about today’s work.

Notes

  • The URL must be unique across all projects globally (not just within the tenant), end with .talkide.app, and contain only lowercase alphanumeric characters and hyphens in the subdomain part.
  • The accent field is mandatory and must be one of the 6 oklch presets defined in the design system.
  • Tech-stack fields are optional in the request DTO. If omitted (recommended path), the BE fills in the team defaults: Kotlin / Spring Boot / TypeScript / Vue.js.
  • The legacy single techStack string field has been removed in favour of 4 structured fields. The DB column tech_stack is dropped and replaced by backend_language, backend_framework, frontend_language, frontend_framework.
  • Project + first conversation are created in a single transaction. If conversation creation fails, the project is rolled back (no orphan project without a conversation).
sequenceDiagram
    actor User

    User->>+FE: opens New Project screen

    FE-->>User: Pseudo-Mara: greeting bubble (i18n)

    User->>FE: types Name (inline input)
    FE->>FE: validate Name (not blank, max 100)

    User->>FE: types Description (inline textarea)
    FE->>FE: validate Description (max 500)

    User->>FE: types URL slug (inline input + .talkide.app suffix)

    loop debounce 400 ms while typing
        FE->>+BE: GET /api/v1/projects/check-url?url={slug}.talkide.app <br> Authorization: Bearer {accessToken}
        BE->>DB: check if URL is already taken
        BE->>-FE: 200 OK <br> UrlAvailabilityResponse
        FE-->>User: show availability chip (checking / available / taken / invalid)
    end

    User->>FE: picks Accent (one of 6 oklch chips)

    FE-->>User: Pseudo-Mara: tech-stack offer bubble + 2 chips

    alt user picks "ANO (doporučeno)"
        FE->>FE: skip tech-stack questions
    else user picks "Vyberu si svůj tech stack"
        User->>FE: picks BE language
        User->>FE: picks BE framework
        User->>FE: picks FE language
        User->>FE: picks FE framework
    end

    FE->>+BE: POST /api/v1/projects <br> Authorization: Bearer {accessToken} <br> CreateProjectRequest

    BE->>BE: validate request
    alt request is invalid
        BE-->>FE: 400 Bad Request <br> ErrorResponse
    end

    BE->>DB: check if URL is already taken
    alt URL already taken
        BE-->>FE: 409 Conflict <br> ErrorResponse
    end

    BE->>BE: apply tech-stack defaults for omitted fields

    BE->>DB: insert project (status = DRAFT)

    BE->>BE: StartConversationUseCase (auto-start, no first message)
    BE->>DB: insert conversation (status = ACTIVE, title = "New project")

    BE->>-FE: 201 Created <br> CreateProjectResponse (includes conversationId)

    FE->>FE: route to /workspace/:projectId

    FE->>+BE: GET /api/v1/projects/{projectId}/conversations/{conversationId}
    BE->>-FE: 200 OK <br> ConversationDetailResponse

    FE->>+BE: POST /api/v1/projects/{projectId}/conversations/{conversationId}/auto-start <br> (SSE)
    BE->>BE: spawn Mara (LLM) with full context (incl. project.description)
    BE-->>FE: SSE stream — Mara opening message (no greeting, asks what we work on)
    BE->>-FE: SSE end

    FE-->>-User: workspace ready, Mara has spoken

Check URL Availability

GET /api/v1/projects/check-url?url=wildwood-bakery.talkide.app (no request body)

200 OK UrlAvailabilityResponse:

{
  "data": {
    "available": true
  }
}

400 Bad Request (invalid URL format) ErrorResponse:

{
  "status": 400,
  "code": "VALIDATION_ERROR",
  "message": "Validation failed",
  "errors": [
    { "field": "url", "message": "must end with .talkide.app and contain only lowercase alphanumeric characters and hyphens" }
  ]
}

401 Unauthorized (missing or invalid access token) ErrorResponse:

{
  "status": 401,
  "code": "AUTHENTICATION_FAILED",
  "message": "Access token is missing or invalid"
}

Create Project

POST /api/v1/projects CreateProjectRequest (recommended-defaults variant):

{
  "name": "Wildwood Bakery",
  "description": "Online ordering for a neighborhood bakery",
  "url": "wildwood-bakery.talkide.app",
  "accent": "oklch(0.78 0.15 70)"
}

POST /api/v1/projects CreateProjectRequest (custom tech-stack variant):

{
  "name": "Wildwood Bakery",
  "description": "Online ordering for a neighborhood bakery",
  "url": "wildwood-bakery.talkide.app",
  "accent": "oklch(0.78 0.15 70)",
  "backendLanguage": "Java",
  "backendFramework": "Quarkus",
  "frontendLanguage": "TypeScript",
  "frontendFramework": "React"
}

201 Created CreateProjectResponse:

{
  "data": {
    "id": 1,
    "conversationId": 8,
    "name": "Wildwood Bakery",
    "description": "Online ordering for a neighborhood bakery",
    "status": "DRAFT",
    "url": "wildwood-bakery.talkide.app",
    "accent": "oklch(0.78 0.15 70)",
    "backendLanguage": "Kotlin",
    "backendFramework": "Spring Boot",
    "frontendLanguage": "TypeScript",
    "frontendFramework": "Vue.js",
    "progress": null,
    "createdAt": "2026-05-03T10:00:00Z",
    "updatedAt": "2026-05-03T10:00:00Z"
  }
}

400 Bad Request (validation) ErrorResponse:

{
  "status": 400,
  "code": "VALIDATION_ERROR",
  "message": "Validation failed",
  "errors": [
    { "field": "name", "message": "must not be blank" }
  ]
}

401 Unauthorized (missing or invalid access token) ErrorResponse:

{
  "status": 401,
  "code": "AUTHENTICATION_FAILED",
  "message": "Access token is missing or invalid"
}

409 Conflict (URL already taken) ErrorResponse:

{
  "status": 409,
  "code": "CONFLICT_PROJECT",
  "message": "URL is already taken by another project"
}

Frontend

Validations

FieldConstraintsSizePatternNote
namenot_blank1 - 100Mandatory; Next disabled until non-blank
description(optional)0 - 500Counter shown inline
urlnot_blank1 - 253^[a-z0-9-]+\.talkide\.app$Auto-prefilled from name slug; live availability check (400 ms debounce); Next disabled until valid AND available
accentnot_blankOne of the 6 oklch presets defined in the design system
backendLanguage(optional)One of: Kotlin / Java / TypeScript / Python (only sent if user picked custom path)
backendFramework(optional)One of: Spring Boot / Quarkus / NestJS / Django
frontendLanguage(optional)One of: TypeScript / JavaScript
frontendFramework(optional)One of: Vue.js / React / Svelte

Pseudo-Mara behaviour

  • Pseudo-Mara is rendered as a chat timeline; each step adds a new bubble + inline InteractivePrompt.
  • No backend/LLM calls during the wizard, except the URL availability check.
  • Each user response is rendered as a user bubble below Pseudo-Mara’s question (mirrors the real chat experience).
  • “Back” / edit-previous-step is allowed: clicking a previous answer collapses subsequent steps and re-opens that step.
  • i18n keys live under createProject.* (e.g. createProject.greeting, createProject.askName, createProject.askTechStackOffer, createProject.recommendedYes, createProject.recommendedNo).

Backend

Validations

FieldConstraintsSizePatternNote
namenot_blank1 - 100
description(optional)0 - 500
urlnot_blank1 - 253^[a-z0-9-]+\.talkide\.app$Must be globally unique
accentnot_blank, in_setMust match one of the 6 oklch presets
backendLanguage(optional), in_setIf null → defaults to Kotlin
backendFramework(optional), in_setIf null → defaults to Spring Boot
frontendLanguage(optional), in_setIf null → defaults to TypeScript
frontendFramework(optional), in_setIf null → defaults to Vue.js

Schema changes (Liquibase, in-place edit allowed — pre-production)

ChangeDetail
DROPproject.tech_stack (VARCHAR)
ADDproject.backend_language VARCHAR NOT NULL DEFAULT 'Kotlin'
ADDproject.backend_framework VARCHAR NOT NULL DEFAULT 'Spring Boot'
ADDproject.frontend_language VARCHAR NOT NULL DEFAULT 'TypeScript'
ADDproject.frontend_framework VARCHAR NOT NULL DEFAULT 'Vue.js'

The entity model in model/README.md is updated accordingly.

Atomic project + conversation creation

CreateProjectUseCase orchestrates both steps in a single transaction:

  1. Insert project (status = DRAFT).
  2. Call StartConversationUseCase.autoStart(projectId) — creates a conversation (status = ACTIVE, title = "New project", no first user message, sessionId = null).
  3. Return CreateProjectResponse with id (project) AND conversationId.

If step 2 fails for any reason, the whole transaction rolls back — no orphan project.

The auto-start variant is described in UC-04002.

Mara context (mara-context.md) — required updates by BE

The <project-path>/CLAUDE.md template rendered by BE (see specification/mara-context.md) MUST be updated to support the conversational create flow:

  1. BUG FIX — the current template does not include {{project.description}}. Mara therefore never receives the project description as context. Add a Popis line under Projekt.
  2. Replace {{project.techStack}} (currently absent in the template, but planned) with four structured lines for the new fields, e.g.:
    - **Backend**: {`{`}{`{`}project.backendLanguage{`}`}{`}`} / {`{`}{`{`}project.backendFramework{`}`}{`}`}
    - **Frontend**: {`{`}{`{`}project.frontendLanguage{`}`}{`}`} / {`{`}{`{`}project.frontendFramework{`}`}{`}`}
    
  3. Welcome instruction — add an explicit section instructing Mara:

    Pseudo-Mara již proběhla a uživatele přivítala. Nezdrav. Stručně se zeptej, na čem dnes budeme pracovat — využij popis projektu jako kontext.

These changes preserve determinism (pure projection of stable DB state — no timestamps, no nonces) and therefore do not break the prompt cache contract.

Test Cases

GIVENWHENTHEN
authenticated user, valid request with recommended defaults (no tech-stack fields)POST /projects is called201 Created; project in DRAFT; tech-stack defaults applied (Kotlin/Spring Boot/TypeScript/Vue.js); response contains conversationId of the auto-started conversation
authenticated user, valid request with custom tech-stack (all 4 fields)POST /projects is called201 Created; project in DRAFT; supplied tech-stack values stored as-is; response contains conversationId
authenticated user, valid request with descriptionPOST /projects is called201 Created; description stored on project; later renders into Mara’s CLAUDE.md context
authenticated user, valid request with only some tech-stack fieldsPOST /projects is called201 Created; missing tech-stack fields filled with defaults
authenticated user, URL already taken by another projectPOST /projects is called409 CONFLICT_PROJECT error response is returned; no project and no conversation created
name is blankPOST /projects is called400 VALIDATION_ERROR error response is returned
name longer than 100 charactersPOST /projects is called400 VALIDATION_ERROR error response is returned
description longer than 500 charactersPOST /projects is called400 VALIDATION_ERROR error response is returned
URL does not end with .talkide.appPOST /projects is called400 VALIDATION_ERROR error response is returned
URL contains uppercase charactersPOST /projects is called400 VALIDATION_ERROR error response is returned
accent is blankPOST /projects is called400 VALIDATION_ERROR error response is returned
accent is not one of the 6 oklch presetsPOST /projects is called400 VALIDATION_ERROR error response is returned
backendLanguage is not in allowed setPOST /projects is called400 VALIDATION_ERROR error response is returned
backendFramework / frontendLanguage / frontendFramework not in allowed setPOST /projects is called400 VALIDATION_ERROR error response is returned
auto-conversation creation fails (simulated DB error in StartConversationUseCase)POST /projects is calledtransaction rolls back; no project, no conversation persisted; 5xx returned
invalid request (empty body)POST /projects is called400 VALIDATION_ERROR error response is returned
no Authorization headerPOST /projects is called401 AUTHENTICATION_FAILED error response is returned
available URLGET /projects/check-url?url=fresh-name.talkide.app is called200 OK with available=true
URL already takenGET /projects/check-url?url=taken-name.talkide.app is called200 OK with available=false
URL with invalid formatGET /projects/check-url?url=INVALID is called400 VALIDATION_ERROR error response is returned
no Authorization headerGET /projects/check-url is called401 AUTHENTICATION_FAILED error response is returned

Frontend Test Cases (component / e2e)

GIVENWHENTHEN
user opens New Project screengreeting bubble renders{firstName} is interpolated from current user profile
user has not yet typed a nameclicks Next on Name stepNext is disabled (no submit attempt)
user typed slug “wildwood-bakery”, BE returns available=true400 ms debounce elapsesavailability chip shows “available”; Next becomes enabled
user typed slug “wildwood-bakery”, BE returns available=false400 ms debounce elapsesavailability chip shows “taken”; Next stays disabled
user typed slug “INVALID” (uppercase)format validation runsavailability chip shows “invalid format”; no BE call is fired
user picks “ANO (doporučeno)” on tech-stack offersubmit firesrequest body omits the 4 tech-stack fields
user picks “Vyberu si svůj tech stack”flow continues4 additional chip prompts appear in order; submit fires only after all 4 are answered
BE returns 201 with conversationId = 8navigation runsFE routes to /workspace/{projectId} and loads conversation 8
workspace loaded, conversation has zero messagesauto-start streamsMara’s opening SSE message arrives without any user input; the message does not contain a greeting (e.g. no “Ahoj”) and references the project description

Was this page helpful?

Thanks for the feedback.