feat(onboarding): resolve milestone template per module (config over code)
Widens milestoneTemplate(db, moduleCode?) to resolve project.milestone_template:<CODE> before the global project.milestone_template setting, falling back to FALLBACK_TEMPLATE. ensureProjectMilestones now looks up the client_module's module code and resolves the template through it, so each module can carry its own onboarding checklist as a dated setting row instead of one hardcoded global list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>feat/client-detail-redesign
parent
6bc92bace3
commit
1e77792beb
@ -0,0 +1,30 @@
|
||||
// apps/hq/test/milestones-templates.test.ts — per-module onboarding template resolution.
|
||||
import { describe, it, expect, beforeEach } from 'vitest'
|
||||
import { openDb, type DB } from '../src/db'
|
||||
import { milestoneTemplate } from '../src/repos-milestones'
|
||||
|
||||
describe('per-module milestone templates', () => {
|
||||
let db: DB
|
||||
beforeEach(() => { db = openDb(':memory:') })
|
||||
|
||||
it('falls back to the global template when no module-specific one exists', async () => {
|
||||
await db.run(`INSERT INTO setting (key, value) VALUES ('project.milestone_template', ?)`,
|
||||
JSON.stringify([{ key: 'a', label: 'A' }]))
|
||||
expect(await milestoneTemplate(db, 'SMS')).toEqual([{ key: 'a', label: 'A' }])
|
||||
})
|
||||
|
||||
it('prefers the module-specific template over the global one', async () => {
|
||||
await db.run(`INSERT INTO setting (key, value) VALUES ('project.milestone_template', ?)`,
|
||||
JSON.stringify([{ key: 'a', label: 'A' }]))
|
||||
await db.run(`INSERT INTO setting (key, value) VALUES ('project.milestone_template:SMS', ?)`,
|
||||
JSON.stringify([{ key: 'doc', label: 'Document collection' }]))
|
||||
expect(await milestoneTemplate(db, 'SMS')).toEqual([{ key: 'doc', label: 'Document collection' }])
|
||||
// A different module still gets the global one.
|
||||
expect(await milestoneTemplate(db, 'RTGS')).toEqual([{ key: 'a', label: 'A' }])
|
||||
})
|
||||
|
||||
it('falls back to the code default when nothing is seeded', async () => {
|
||||
const t = await milestoneTemplate(db, 'SMS')
|
||||
expect(t.map((e) => e.key)).toContain('go_live')
|
||||
})
|
||||
})
|
||||
Loading…
Reference in New Issue