Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
26491cd
docs(25): create phase plan for default template schema
therealbrad Mar 19, 2026
a739d82
feat(25-01): Add defaultCaseExportTemplate relation to Projects model
therealbrad Mar 19, 2026
0cabe15
chore(25-01): Regenerate ZenStack/Prisma artifacts after adding defau…
therealbrad Mar 19, 2026
a0d6be4
docs(25-01): complete default-template-schema plan
therealbrad Mar 19, 2026
8e52c46
docs(phase-25): complete phase execution
therealbrad Mar 19, 2026
83a47a5
docs(26): create phase plan for admin assignment UI
therealbrad Mar 19, 2026
30b4775
feat(26-01): Add project admin access rules to CaseExportTemplateProj…
therealbrad Mar 19, 2026
64ea864
docs(26-01): complete admin assignment access rules plan
therealbrad Mar 19, 2026
1492983
feat(26-02): create ExportTemplateAssignmentSection component
therealbrad Mar 19, 2026
b6b55c5
feat(26-02): integrate ExportTemplateAssignmentSection into quickscri…
therealbrad Mar 19, 2026
ba1d6ed
docs(26-02): complete export template assignment UI plan
therealbrad Mar 19, 2026
87e79d2
refactor(26-02): refine export template assignment UI based on review
therealbrad Mar 19, 2026
771de08
docs(26-02): complete export template assignment UI plan
therealbrad Mar 19, 2026
aa762cc
docs(phase-26): complete phase execution
therealbrad Mar 19, 2026
7aeeb85
docs(27-export-dialog-filtering): create phase plan
therealbrad Mar 19, 2026
c96dcd0
feat(27-01): add noAvailableTemplates translation key
therealbrad Mar 19, 2026
398da5c
feat(27-01): filter QuickScript templates by project assignment and p…
therealbrad Mar 19, 2026
7f19dcb
docs(27-01): complete export dialog filtering plan
therealbrad Mar 19, 2026
938a770
docs(phase-27): complete phase execution
therealbrad Mar 19, 2026
bf8bef2
docs: add per-project export template assignment documentation
therealbrad Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .planning/REQUIREMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Requirements: Per-Project Export Template Assignment

**Defined:** 2026-03-18
**Core Value:** Teams can plan, execute, and track testing across manual and automated workflows in one place — with AI assistance to reduce repetitive work.
**Issue:** GitHub #85

## v2.1 Requirements

Requirements for per-project export template assignment. Each maps to roadmap phases.

### Schema

- [x] **SCHEMA-01**: CaseExportTemplateProjectAssignment join model links CaseExportTemplate to Project (already exists)
- [x] **SCHEMA-02**: Project has a default case export template relation

### Admin UI

- [x] **ADMIN-01**: Admin can assign/unassign export templates to a project in project settings
- [x] **ADMIN-02**: Admin can set a default export template for a project

### Export Dialog

- [x] **EXPORT-01**: Export dialog only shows templates assigned to the current project
- [x] **EXPORT-02**: Project default template is pre-selected in the export dialog
- [x] **EXPORT-03**: If no templates are assigned to a project, all enabled templates are shown (backward compatible)

## Future Requirements

None — this is a self-contained feature.

## Out of Scope

| Feature | Reason |
|---------------------------------------|-----------------------------------------------------------------|
| Per-user template preferences | Not in issue #85, could be future enhancement |
| Template creation from project settings | Templates are managed globally in admin; projects only assign existing ones |
| Template ordering per project | Unnecessary complexity for v2.1 |

## Traceability

Which phases cover which requirements. Updated during roadmap creation.

| Requirement | Phase | Status |
|-------------|----------|------------------|
| SCHEMA-01 | — | Complete (exists) |
| SCHEMA-02 | Phase 25 | Complete |
| ADMIN-01 | Phase 26 | Complete |
| ADMIN-02 | Phase 26 | Complete |
| EXPORT-01 | Phase 27 | Complete |
| EXPORT-02 | Phase 27 | Complete |
| EXPORT-03 | Phase 27 | Complete |

**Coverage:**

- v2.1 requirements: 7 total
- Already complete: 1 (SCHEMA-01)
- Remaining: 6
- Mapped: 6/6

---

*Requirements defined: 2026-03-18*
*Last updated: 2026-03-18 after roadmap creation (Phases 25-27)*
388 changes: 388 additions & 0 deletions .planning/ROADMAP.md

Large diffs are not rendered by default.

82 changes: 82 additions & 0 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
gsd_state_version: 1.0
milestone: v2.1
milestone_name: Per-Project Export Template Assignment
status: planning
stopped_at: Completed 27-export-dialog-filtering/27-01-PLAN.md
last_updated: "2026-03-19T05:37:52.328Z"
last_activity: 2026-03-18 — Roadmap created for v2.1 (Phases 25-27)
progress:
total_phases: 19
completed_phases: 3
total_plans: 4
completed_plans: 4
percent: 0
---

# State

## Project Reference

See: .planning/PROJECT.md (updated 2026-03-18)

**Core value:** Teams can plan, execute, and track testing across manual and automated workflows in one place — with AI assistance to reduce repetitive work.
**Current focus:** v2.1 Per-Project Export Template Assignment — Phase 25: Default Template Schema

## Current Position

Phase: 25 of 27 (Default Template Schema)
Plan: — of TBD in current phase
Status: Ready to plan
Last activity: 2026-03-18 — Roadmap created for v2.1 (Phases 25-27)

Progress: [░░░░░░░░░░] 0% (v2.1 phases)

## Performance Metrics

**Velocity:**
- Total plans completed (v2.1): 0
- Average duration: —
- Total execution time: —

**By Phase:**

| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| - | - | - | - |

## Accumulated Context
| Phase 25-default-template-schema P01 | 5min | 2 tasks | 5 files |
| Phase 26-admin-assignment-ui P01 | 5 | 1 tasks | 1 files |
| Phase 26 P02 | 15min | 2 tasks | 3 files |
| Phase 26-admin-assignment-ui P02 | 45min | 3 tasks | 4 files |
| Phase 27-export-dialog-filtering P01 | 15min | 2 tasks | 2 files |

### Decisions

- Follow TemplateProjectAssignment pattern (existing pattern for case field template assignments)
- Backward compatible fallback: no assignments = show all enabled templates
- SCHEMA-01 already complete (CaseExportTemplateProjectAssignment join model exists in schema.zmodel)
- ZenStack hooks for CaseExportTemplateProjectAssignment are already generated
- [Phase 25-default-template-schema]: Used onDelete: SetNull on defaultCaseExportTemplateId FK so deleting a CaseExportTemplate clears the default on referencing projects
- [Phase 25-default-template-schema]: Named relation 'ProjectDefaultExportTemplate' disambiguates from CaseExportTemplateProjectAssignment join-table relation
- [Phase 26-admin-assignment-ui]: Mirrored Projects model access pattern for project-admin-scoped create/delete on CaseExportTemplateProjectAssignment
- [Phase 26-admin-assignment-ui]: Added translation keys in Task 1 commit because TypeScript validates next-intl keys against en-US.json at compile time
- [Phase 26-admin-assignment-ui]: MultiAsyncCombobox chosen over checkbox list for better UX with large template lists
- [Phase 26-admin-assignment-ui]: selectedTemplates stored as TemplateOption[] objects so badge data available without re-lookup
- [Phase 27-export-dialog-filtering]: Used templateId (not caseExportTemplateId) — join model field name per schema.zmodel
- [Phase 27-export-dialog-filtering]: filteredTemplates pattern: fetch global templates + assignment filter in useMemo for project-scoped template display

### Pending Todos

None yet.

### Blockers/Concerns

None yet.

## Session Continuity

Last session: 2026-03-19T05:35:21.836Z
Stopped at: Completed 27-export-dialog-filtering/27-01-PLAN.md
Resume file: None
169 changes: 169 additions & 0 deletions .planning/phases/25-default-template-schema/25-01-PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
---
phase: 25-default-template-schema
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- testplanit/schema.zmodel
autonomous: true
requirements:
- SCHEMA-02

must_haves:
truths:
- "Project model has an optional defaultCaseExportTemplate relation to CaseExportTemplate"
- "Setting defaultCaseExportTemplateId on a project persists a valid FK to CaseExportTemplate"
- "Clearing defaultCaseExportTemplateId (setting to null) persists correctly"
- "ZenStack and Prisma generation succeeds without errors"
- "Deleting a CaseExportTemplate that is a project default sets the FK to null (SetNull)"
artifacts:
- path: "testplanit/schema.zmodel"
provides: "Project model with defaultCaseExportTemplate relation"
contains: "defaultCaseExportTemplateId"
key_links:
- from: "Projects.defaultCaseExportTemplateId"
to: "CaseExportTemplate.id"
via: "@relation FK"
pattern: "defaultCaseExportTemplate\\s+CaseExportTemplate"
---

<objective>
Add a nullable `defaultCaseExportTemplateId` FK and relation to the Project model in schema.zmodel, then regenerate ZenStack/Prisma artifacts and push the schema to the database.

Purpose: Enables per-project default export template selection (SCHEMA-02). Phase 26 will build the admin UI to set this value; Phase 27 will use it to pre-select a template in the export dialog.

Output: Updated schema.zmodel with the new relation, regenerated Prisma client and ZenStack hooks, database schema updated.
</objective>

<execution_context>
@/Users/bderman/.claude/get-shit-done/workflows/execute-plan.md
@/Users/bderman/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/25-default-template-schema/25-CONTEXT.md

<interfaces>
<!-- Key types and contracts the executor needs. Extracted from schema.zmodel. -->

From testplanit/schema.zmodel (Project model, lines 334-467):
```zmodel
model Projects {
// ... existing fields ...
defaultRoleId Int?
defaultRole Roles? @relation("ProjectDefaultRole", fields: [defaultRoleId], references: [id])
// ... existing fields ...
assignedExportTemplates CaseExportTemplateProjectAssignment[]
quickScriptEnabled Boolean @default(false)
// access control rules follow
}
```

From testplanit/schema.zmodel (CaseExportTemplate model, lines 785-806):
```zmodel
model CaseExportTemplate {
id Int @id @default(autoincrement())
name String @unique @length(1)
// ... other fields ...
projects CaseExportTemplateProjectAssignment[]

@@deny('all', !auth())
@@allow('all', auth().access == 'ADMIN')
@@allow('read', auth().access != null)
}
```
</interfaces>
</context>

<tasks>

<task type="auto">
<name>Task 1: Add defaultCaseExportTemplate relation to Project model</name>
<files>testplanit/schema.zmodel</files>
<read_first>
- testplanit/schema.zmodel (lines 334-467 for Project model, lines 785-806 for CaseExportTemplate model)
</read_first>
<action>
In `testplanit/schema.zmodel`, add two new fields to the `Projects` model, placed after the `assignedExportTemplates` line (line 377) and before `quickScriptEnabled`:

```zmodel
defaultCaseExportTemplateId Int?
defaultCaseExportTemplate CaseExportTemplate? @relation("ProjectDefaultExportTemplate", fields: [defaultCaseExportTemplateId], references: [id], onDelete: SetNull)
```

Then add a back-relation on the `CaseExportTemplate` model. After the existing `projects` line (line 801), add:

```zmodel
defaultForProjects Projects[] @relation("ProjectDefaultExportTemplate")
```

Key details:
- Use `onDelete: SetNull` so deleting a CaseExportTemplate clears the default on any project referencing it (per CONTEXT.md discretion decision)
- Use a named relation `"ProjectDefaultExportTemplate"` to disambiguate from the existing join-table relation via `CaseExportTemplateProjectAssignment`
- The FK is nullable (`Int?`) and the relation is optional (`CaseExportTemplate?`) since projects may not have a default
- No access control changes needed on Project model (existing rules cover all fields)
</action>
<verify>
<automated>cd testplanit && grep -n "defaultCaseExportTemplateId" schema.zmodel && grep -n "defaultCaseExportTemplate " schema.zmodel && grep -n "defaultForProjects" schema.zmodel && grep -n "ProjectDefaultExportTemplate" schema.zmodel</automated>
</verify>
<acceptance_criteria>
- schema.zmodel contains `defaultCaseExportTemplateId Int?` inside the Projects model
- schema.zmodel contains `defaultCaseExportTemplate CaseExportTemplate? @relation("ProjectDefaultExportTemplate", fields: [defaultCaseExportTemplateId], references: [id], onDelete: SetNull)` inside the Projects model
- schema.zmodel contains `defaultForProjects Projects[] @relation("ProjectDefaultExportTemplate")` inside the CaseExportTemplate model
- The new fields appear after `assignedExportTemplates` and before `quickScriptEnabled` in the Projects model
</acceptance_criteria>
<done>Project model has nullable FK and optional relation to CaseExportTemplate for per-project default; CaseExportTemplate has back-relation</done>
</task>

<task type="auto">
<name>Task 2: Regenerate ZenStack/Prisma and push schema</name>
<files>testplanit/schema.zmodel</files>
<read_first>
- testplanit/schema.zmodel (verify Task 1 changes are present)
- testplanit/package.json (confirm `generate` script exists)
</read_first>
<action>
Run `pnpm generate` from the `testplanit/` directory. This command:
1. Runs `zenstack generate` which regenerates all ZenStack hooks in `lib/hooks/`
2. Runs `prisma db push` which applies the schema change to the database (adds nullable `defaultCaseExportTemplateId` column to Projects table)

The nullable FK addition is safe for existing data -- all existing rows get NULL automatically.

After generation succeeds, verify the generated Prisma schema includes the new field by checking `testplanit/prisma/schema.prisma` for `defaultCaseExportTemplateId`.
</action>
<verify>
<automated>cd testplanit && pnpm generate 2>&1 | tail -20 && grep "defaultCaseExportTemplateId" prisma/schema.prisma</automated>
</verify>
<acceptance_criteria>
- `pnpm generate` exits with code 0
- `testplanit/prisma/schema.prisma` contains `defaultCaseExportTemplateId`
- `testplanit/prisma/schema.prisma` contains `defaultCaseExportTemplate`
- No TypeScript compilation errors related to the new fields
</acceptance_criteria>
<done>ZenStack hooks regenerated, Prisma client updated, database schema pushed with new nullable FK column on Projects table</done>
</task>

</tasks>

<verification>
1. `grep "defaultCaseExportTemplateId" testplanit/schema.zmodel` returns the FK field
2. `grep "defaultCaseExportTemplate " testplanit/schema.zmodel` returns the relation field
3. `grep "defaultForProjects" testplanit/schema.zmodel` returns the back-relation on CaseExportTemplate
4. `grep "defaultCaseExportTemplateId" testplanit/prisma/schema.prisma` confirms Prisma schema was generated
5. `cd testplanit && pnpm generate` completes without errors
</verification>

<success_criteria>
- Project model in schema.zmodel has `defaultCaseExportTemplateId Int?` and `defaultCaseExportTemplate CaseExportTemplate?` relation
- CaseExportTemplate model has `defaultForProjects Projects[]` back-relation
- `pnpm generate` succeeds (ZenStack + Prisma generation + db push)
- Generated Prisma schema and hooks include the new relation
</success_criteria>

<output>
After completion, create `.planning/phases/25-default-template-schema/25-01-SUMMARY.md`
</output>
Loading
Loading