The '${contestId}-notice' / '${contestId}-exam' id template was
duplicated in WallTab and the Seeder. Extract wallLinkKey(contestId,
kind) in the Wall module, import it at both call sites, and add three
tests covering format stability (regression for the 'second save
replaces first save' behaviour the form relies on).
Discriminator literals in RegisterStudySessionUseCase,
DeleteStudySessionUseCase, registerCommands, SessionsTab's type
select, and the Seeder are now expressed via the StudySessionType
constant. The on-disk string value is unchanged ('questions'),
so existing data and the CSV-output literal tests keep working.
LeifPluginData had two version fields; nothing read 'version' so it
is removed. schemaVersion is the canonical field used by
DataMigrations and remains untouched.
Drop the 'any' signatures on migrate/migrateV1toV2/migrateV2toV3 in
favour of LeifPluginData, and the now-unused VersionedData interface.
Missing schemaVersion is treated as 1 via the existing ?? fallback,
so callers that pass unversioned plugin data keep working.
Contest.wall is now Wall (was an inline any[] shape) and defaults to
new Wall(). EntityRepository becomes generic over EntityCollectionKey
and reaches the live LeifPluginData via a single typed accessor, removing
the previous six 'as unknown as T[]' casts and the dubious assignment
cast. The RepositoryFactory port and concrete factory use EntityCollections
to infer the per-repo entity type, so use cases no longer pass <Entity>
(type-inferred from the key now). Net: 17 baseline typecheck errors drop
to 7.
Add a minimal i18n layer (src/ui/i18n.ts) with a pt-BR bundle and a t()
lookup. Route the command names, tab labels and the common action buttons
(Cancelar/Criar/Editar/Excluir/Fechar) through t(). Standardize all
command names on Portuguese so the palette is consistent (was a mix of
English and one Portuguese command).
Closes#10
- Add tests for CsvExportService (headers, escaping, empty, nulls).
- Add tests for ExportToCsvUseCase (sessions/contests export, filtering).
- Add tests for DataMigrationService (version stamping, dedup,
idempotency).
- Rename the duplicate 'rejects a questions session...' it() in
LeifView.test.ts so both names are unique and accurate.
Closes#8
Replace 7 Date.now()-based ID generation sites (SessionsTab, ItemsTab,
TopicsTab, CycleTab, registerCommands, CreateStudyItemUseCase) with a
single createId factory using crypto.randomUUID with a fallback, so two
entities created in the same millisecond no longer collide.
Closes#7
- AdvanceCycleUseCase and ReorderSubjectsUseCase now throw ValidationError
instead of plain Error for domain rule violations.
- Add DomHelpers.runGuarded error-boundary helper and use it in
registerCommands (advance cycle, cycle snapshot, summary) to remove
repeated try/catch + Notice boilerplate.
Closes#6
- Delete SubjectService, StudySessionService, QuestionNotebookService
(only exercised by tests; logic lives in use cases) and DomainServices.test.ts.
- Consolidate notifyError into DomHelpers.notifyError (with shared
NoActiveContestError handling) and drop the 6 per-component copies.
- Extract SubjectPicker (getSelectedSubject + create) shared by ItemsTab,
TopicsTab and LeifView.
- Dedupe LeifTabId/TABS: LeifView now imports the constants version.
Closes#5
- eslint (typescript-eslint) + prettier config with a lint script.
- Add a Lint step to the CI workflow (runs on PRs and master).
- Tighten tsconfig: noImplicitReturns, noFallthroughCasesInSwitch.
Closes#4