Organizing Cases: Projects & Sections
Once you have more than a handful of YAMLs on the agent, the flat Tests list becomes hard to navigate. Two orthogonal axes keep it tidy:
-
Project — a first-class container (TestRail-like), stored in a registry. One case belongs to at most one project. Used by the Project filter.
-
Section — free-text metadata copied from the TestRail section (e.g.
TR-181,TR-181 Mesh). The Tests list groups on it.
Both are pure organisation — they never change how a case converts or runs.
|
At a glance
|
Projects Registry
A project is a row in the projects SQLite table (scripts/case_db.py), sharing
the same DB file as the auth layer. Columns: name (primary key), description,
testrail_project_id, created_by, created_at.
| Endpoint | Role | Purpose |
|---|---|---|
|
any authed |
List projects, each with a live
|
|
admin / editor |
Create a project ( |
|
admin / editor |
Rename and/or set
|
|
admin / editor |
Delete the project (see Unassigned below). |
|
admin / editor |
Bulk-assign a list of files to one project. |
The "Unassigned" bucket
There is no literal Unassigned row in the registry. A case whose project is
empty ("") is unassigned, and the UI surfaces those under a virtual
Unassigned option in the Project filter.
Deleting a project does not delete its cases. The
DELETE /api/projects/{name} handler first walks every YAML, and for each case
that belonged to the deleted project it clears the project field (orphans
it to Unassigned), then removes the registry row. No test is ever lost by a
project delete.
|
Importing from TestRail auto-registers the project (insert-if-absent via
ensure_project, created_by="testrail-import"), so you rarely create one by
hand. The + New project action (POST /api/projects) is for projects you
want to exist before any case lands in them.
|
Section Grouping & the Project Filter
The Tests tab list is sorted by section first, then by case ID, so cases
sharing a section sit together. The section value comes straight from TestRail
(test_case.section) and is editable in the Editor.
Above the list, a Project dropdown narrows what you see:
-
All projects — no project filter (default).
-
Unassigned — only cases with an empty
project. -
<name> (N) — only that project’s cases;
Nis the live count.
The filter is independent of the Portal filter and the search box — they compose (project AND portal AND text match). The same dropdown appears on the Editor tab.
Case Metadata Fields
Beyond section, each case carries a small set of organisational fields.
project and section live at the top level of test_case; the rest live under
test_case.metadata. They surface in the list as pills/links and in the Editor
as form inputs.
| Field | Stored as | Rendering |
|---|---|---|
Project |
|
Drives the Project filter and |
Section |
|
Free text; groups the list. |
Reference |
|
A Jira issue key (e.g. |
Priority |
|
A coloured pill — Critical (red), High (amber), Medium (blue), Low (green). |
Type |
|
A grey pill (e.g. |
Author |
|
Who imported vs. who last saved an edit. Set automatically; not editable by hand. |
The jira_base_url is read from Settings and exposed (read-only,
non-secret) at GET /api/ui-config. Leave it blank and references render as
plain text instead of links.
|
Populating the Fields
There are three ways org fields get filled, from most to least automatic.
1. TestRail import (automatic)
Importing a case resolves and registers its
Project from the case’s TestRail project/suite, and maps Priority /
Type / Reference from the TestRail priority_id / type_id / refs
into metadata. Bare-number refs are key-ified by the converter using a Jira
prefix (e.g. 11278 → DEV-11278).
2. Manual edit (Editor)
The Editor form has Project (dropdown),
Section, Priority, Type, and Reference inputs. Save persists them
into the YAML and stamps edited_by.
3. Bulk assign (multi-select)
On either the Tests or Editor list, tick several rows and choose a project to assign them all in one shot:
curl -X POST http://ai.friendly-tech.com:8083/api/tests/assign-project \
-H 'Content-Type: application/json' \
-d '{"files":["C7677.yaml","C7681.yaml"],"project":"TR-181 Mesh"}'
Path components in files are rejected (basename-only, no traversal). The
response reports {"assigned": N}.
Backfilling Org Fields (no re-convert)
After you have already imported a corpus, you often want to enrich the existing YAMLs with Project / Reference / Priority / Type pulled fresh from TestRail — without re-running Stage 2 LLM enrichment (which would re-cost and risk jitter) and without bumping the converter cache.
POST /api/testrail/backfill-fields does exactly that. It matches local YAMLs to
TestRail cases by numeric ID, computes the org-field diff, and patches only those
fields.
| Field | Meaning |
|---|---|
|
Required — the TestRail project + suite to read. |
|
Optional — narrow to one section. |
|
Defaults to |
|
Prefixes bare-number refs with a Jira key (e.g. |
# Preview (no write) — see matched / changed counts + per-case diffs
curl -X POST http://ai.friendly-tech.com:8083/api/testrail/backfill-fields \
-H 'Content-Type: application/json' \
-d '{"project_id":1,"suite_id":3,"ref_prefix":"DEV-"}'
# Apply
curl -X POST http://ai.friendly-tech.com:8083/api/testrail/backfill-fields \
-H 'Content-Type: application/json' \
-d '{"project_id":1,"suite_id":3,"ref_prefix":"DEV-","dry_run":false}'
The response carries matched (local YAMLs found in the suite), changed
(cases whose org fields actually differ), and a details list of per-file
diffs. Always run a dry_run first and read the diff before applying.
| Backfill is the right tool after a TestRail re-org (a case moved project, got a priority, gained a Jira ref). Use reimport only when the converted output (tree / parameters / steps) needs to change. |
See Also
-
Importing Tests — auto project/priority/type/ref assignment happens during import.
-
Editor Guide → Core Fields — editing these fields by hand.
-
API Reference — the full
/api/projectsand/api/testrail/backfill-fieldssurface.