Goal of this module

Define TaskFlow's two entities, see the CRUD endpoints each one generates, and create your first records — all without writing or deploying code.

The data model

TaskFlow needs two entities. A Project is a container; a Task belongs to a project via a project_id field. Defining each entity is a single POST /api/{apiname} to the apistudio gateway — {apiname} is a path parameter you choose (by convention create-<entity>), and the entity name comes from entityName in the body. The payload carries a field catalog (UpdateParams) and record key templates (baseKeys).

1 · Define Project

json
POST /api/create-project        # {apiname} = "create-project" (your choice)
{
  "entityName": "project",
  "baseKeys": {
    "pkTemplate": "org#{org};data#project",
    "skTemplate": "project#{id}"
  },
  "UpdateParams": [
    { "name": "id",     "colType": "guid" },
    { "name": "name",   "colType": "string", "validate": true, "minlength": 1 },
    { "name": "status", "colType": "enum", "enumValues": ["active", "archived"] }
  ]
}

2 · Define Task

Task carries the relationship (project_id), a workflow status, a priority (the AI crew will set this in Module 6), an assignee, and a due_date.

json
POST /api/create-task        # {apiname} = "create-task" (your choice)
{
  "entityName": "task",
  "baseKeys": {
    "pkTemplate": "org#{org};data#task",
    "skTemplate": "task#{id}"
  },
  "UpdateParams": [
    { "name": "id",          "colType": "guid" },
    { "name": "title",       "colType": "string", "validate": true, "minlength": 1 },
    { "name": "description", "colType": "string" },
    { "name": "project_id",  "colType": "string", "validate": true },
    { "name": "status",      "colType": "enum", "enumValues": ["todo", "in_progress", "done"] },
    { "name": "priority",    "colType": "enum", "enumValues": ["low", "medium", "high"] },
    { "name": "assignee",    "colType": "string" },
    { "name": "due_date",    "colType": "string" }
  ]
}

What each definition writes

The handler stores the primary create-<entity> definition and generates four more configs — get, list, update, delete. No per-entity table is created; records land in the shared app table under org#…;data#<entity>, scoped to the caller's workspace at runtime.

3 · The routes you now have

Both entities expose a full API on the app gateway immediately. Every route is authenticated with an app token and scoped to the caller's workspace.

http
POST   /app/{orgCode}/create/task       create a record
GET    /app/{orgCode}/item/task/{id}     read one
PUT    /app/{orgCode}/update/task/{id}   update fields
DELETE /app/{orgCode}/delete/task/{id}   delete
GET    /app/{orgCode}/list/task          list (filters, search, paging)
GET    /app/{orgCode}/count/task         { count }

4 · Seed some records

Create a project, then a couple of tasks in it. (You'll get a real app token in Module 3; for now use the console's data tools or a token from your test workspace.)

bash
# a project
curl -X POST https://{domain}.nostackai.com/app/{orgCode}/create/project \
  -H 'Authorization: <app-token>' -H 'Content-Type: application/json' \
  -d '{ "name": "Website relaunch", "status": "active" }'
# -> { "id": "<projectId>" }

# a task in that project
curl -X POST https://{domain}.nostackai.com/app/{orgCode}/create/task \
  -H 'Authorization: <app-token>' -H 'Content-Type: application/json' \
  -d '{ "title": "Draft the homepage copy",
        "description": "Customer keeps emailing about the broken checkout link — urgent",
        "project_id": "<projectId>", "status": "todo" }'

Why writes return only the id

Create and update responses return only the fields in the entity's default response view — by default just id. This avoids echoing the whole record on every write; shape richer responses with views when you need them.

Try it

Define both entities, create one project and two tasks (leave priority unset — the crew fills it in Module 6). Then GET /app/{orgCode}/list/task and confirm both come back. Try GET /app/{orgCode}/count/task too.

Go deeper