DC-172: Enrollment checker API endpoint with plugin integration#64
Closed
jamesmblair wants to merge 54 commits intomainfrom
Closed
DC-172: Enrollment checker API endpoint with plugin integration#64jamesmblair wants to merge 54 commits intomainfrom
jamesmblair wants to merge 54 commits intomainfrom
Conversation
Design documents for the multi-state enrollment checking capability that allows parents/guardians to check Summer EBT enrollment status without logging in. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tion Add POST /api/enrollment/check — a public, unauthenticated endpoint that allows parents/guardians to check children's Summer EBT enrollment status. Delegates state-specific matching to the plugin system via IEnrollmentCheckService. Key changes: - Register IEnrollmentCheckService in MEF plugin conventions - CheckEnrollmentCommandHandler with server-generated correlation IDs - De-identified persistence (birth year only, SHA-256 hashed IPs, no PII) - Per-IP fixed window rate limiting (enrollment-check-policy) - Policy-aware OnRejected handler for correct 429 error messages - EF Core migration for EnrollmentCheckSubmissions table - DesignTimePortalDbContextFactory for EF tooling support - Public partial Program class for WebApplicationFactory support - 8 unit tests + 5 integration tests (437 total, all passing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hard-coded "otp-policy" and "enrollment-check-policy" strings with constants to prevent silent mismatches across controllers and Program.cs configuration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e fallback Add integration tests that load real MEF plugins (DC, CO) and exercise the full HTTP pipeline through to actual backends. Tests skip gracefully when plugin DLLs or credentials are unavailable. Also add a default IEnrollmentCheckService that returns NonMatch when no plugin is loaded, and harden PortalWebApplicationFactory's env var handling to prevent race conditions between test collections. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…line Documents the approach for eliminating env var usage in test factories by changing AddPlugins from an IServiceCollection extension to an IHostBuilder extension. This defers plugin loading to the Build() pipeline where WAF's ConfigureAppConfiguration has already run. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…eCollection Move plugin loading from inline Program.cs execution to a ConfigureServices callback. This runs during Build(), after WAF's ConfigureAppConfiguration, enabling tests to override plugin config via standard .NET patterns instead of environment variables. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ugin loading Update the design doc with corrected approach after discovering that ConfigureHostBuilder.ConfigureServices runs immediately in minimal hosting. Add implementation plan with 6 tasks for the factory delegate approach. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… IServiceCollection" This reverts commit f703121.
Extract MEF loading logic into a singleton that loads lazily on first DI resolution. Takes IConfiguration via constructor injection, so it reads the fully-assembled config including WAF test overrides. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ates Replace eager MEF loading with factory delegates that defer to PluginLoader. AddPlugins no longer takes IConfiguration — config is read at resolution time when it's fully assembled. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…guration Replace env var constructor/dispose lifecycle with standard ConfigureAppConfiguration and in-memory collection. No more process-global state mutation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ureAppConfiguration Replace env var constructor/dispose lifecycle with standard ConfigureAppConfiguration. Config overrides are now scoped to each factory instance instead of mutating process-global state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests no longer mutate process-global state, so [Collection] serialization is unnecessary. Update config override keys from env var format (__) to standard .NET hierarchical format (:). Delete PluginIntegrationCollection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ntials Replace Environment.GetEnvironmentVariable() with ConfigurationBuilder that chains env vars and user secrets, providing a standard secure way to store CBMS API credentials locally while preserving CI compatibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ment-checker # Conflicts: # src/SEBT.Portal.Api/Composition/ServiceCollectionPluginExtensions.cs
Restore the deferred PluginLoader pattern so MEF plugin assemblies load lazily at DI resolution time, when IConfiguration is fully assembled (including WebApplicationFactory test overrides). This fixes plugin integration tests that were broken by eager config reads at startup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Documents the architecture for the new SEBT.EnrollmentChecker.Web app: shared design-system package, SSR/SSG deployment modes, form state model, content pipeline, component structure, and two-workstream implementation plan. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add packages/design-system as a pnpm workspace package (@sebt/design-system). Update .gitignore to allow the top-level packages/ directory, which was previously excluded by the NuGet package-restore ignore rule (**/[Pp]ackages/*). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… paths Copies USWDS bundle, theme, and component SASS files from src/SEBT.Portal.Web/design/sass/ to packages/design-system/design/sass/, updates next.config.ts to resolve SASS includePaths via the @sebt/design-system workspace dependency, and updates styles.scss to forward 'uswds-bundle' without a relative path prefix. Also adds @sebt/design-system as a workspace dependency to the portal's package.json so pnpm creates the required node_modules symlink. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ign-system Copies UI components (Button, InputField, Alert, TextLink), layout components (Header, Footer, HelpSection, SkipNav, LanguageSelector), the I18nProvider, and lib files (i18n, state, links) into packages/design-system/src/. Refactors i18n initialization into an exported initI18n() function so apps supply their own generated locale resources. Adds vitest config and barrel index.ts to the package. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update all portal source files to import components (Alert, Button, InputField, TextLink, layout), providers (I18nProvider), and lib utilities (state, links, i18n) from @sebt/design-system instead of local @/components/ and @/lib/ paths. Delete the now-redundant local source files. Configure next.config.ts with transpilePackages, serverExternalPackages, and webpack aliases to ensure a single React instance and prevent react-i18next from being evaluated in the RSC context. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oviders, and USWDS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- childSchema and enrollmentSchema Zod schemas with request/response types - EnrollmentContext with sessionStorage persistence and CRUD actions - checkEnrollment and getSchools API functions with error handling - useSchools TanStack Query hook - MSW handlers for /api/enrollment/check and /api/enrollment/schools - Fix vitest.config.ts alias ordering so @/content resolves before @ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d, result display) Implements LandingPage, DisclaimerPage, ClosedPage, ChildReviewCard, ChildResultCard, EnrolledSection, and NotEnrolledSection with full TDD coverage. Also adds required i18n keys (heading, cta, editChild, removeChild, enrolledHeading, etc.) to all state/locale content files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…hildFormPage, ReviewPage, ResultsPage) Implements Task 4 of the enrollment checker: school selection dropdown, child info form with Zod validation, add/edit child page, review list page, and results display page. Adds required i18next content keys to all locale files (en/es × co/dc) for personalInfo, confirmInfo, result, and common namespaces. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…missing keys
Update enrollment checker components to reference the key names that the
generate-locales script produces from the state CSVs, rather than the
custom names the implementer invented. Fixes 6 mismatches:
- landing/disclaimer/personalInfo/confirmInfo: t('heading') → t('title')
- personalInfo: t('dobLabel') → t('labelBirthdate')
- confirmInfo: t('addAnotherChild') → t('actionAdd')
Update ChildForm tests to match the new label text ('Birthdate' not
'Date of birth').
Add docs/content/enrollment-checker-missing-csv-keys.md listing the 20
content keys that still need to be added to co.csv and dc.csv before the
manually-written locale JSON files can be removed from version control.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copies CDHS logo, state seal, and translate icon from portal for both CO and DC. Fixes broken images in header and footer.
Fixes i18n namespace collision where portal S3 rows overwrote enrollment checker S1 values for personalInfo and confirmInfo. ADR-0009 documents the decision. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Renders markdown-formatted locale strings as React elements. Supports bold, paragraph breaks, and inline mode. ADR-0010 documents the decision. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ChildFormValues now has separate month, day, year fields for the USWDS memorable-date form pattern. Child type stores composed dateOfBirth as ISO string. Conversion helpers bridge the two. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces single Continue button with Apply now / Aplica ahora. Adds expandable FAQ section with eligibility details. Body text now renders bold markdown via RichText. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Uses USWDS memorable-date pattern with month dropdown to prevent MM/DD transposition. Adds name field hints and switches cancel button to Back label. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrites ChildReviewCard to add Name/Birthdate labels, format dates as "Month, Day Year", include middle initial, and replace Edit/Remove buttons with a single "Update this child's information" link (removing the onRemove prop per Figma design). Rewrites ReviewPage to add a description paragraph, horizontal rules between child cards, Back+Submit button group, and "Add another child" as a text link below. Updates tests to match the new component interfaces. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updates test files that reference old childSchema, dateOfBirth field, and button labels to match the new month/day/year schema and structural component changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- enrollment-checker-figma-comparison.md: visual fidelity gap analysis - design spec: 5 workstreams for closing those gaps - implementation plan: 11 tasks across 4 chunks - regenerated locale resources after section filtering Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The barrel export from @sebt/design-system re-exports react-i18next-dependent modules (I18nProvider, initI18n). When layout.tsx (a Server Component) imported from the barrel, react-i18next was pulled into the RSC bundle causing a createContext error. The previous workaround (serverExternalPackages) fixed that but broke client component SSR with a useMemo null dispatcher error. Fix: use direct subpath imports in layout.tsx and Providers.tsx to keep react-i18next out of the RSC module graph entirely, matching the portal's pattern on main. Remove the now-unnecessary serverExternalPackages config. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Figma verification found two gaps: the review page showed a raw "addAnotherChild" key (missing from all locale files) and the child form's middle name field lacked the "Optional" hint text shown in the design. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nAdd key
Locale JSON files are generated from CSVs — never hand-edit them. The
addAnotherChild key we added manually already exists as actionAdd in the
confirmInfo namespace (generated from the spreadsheet). Updated ReviewPage
to use t('actionAdd') from confirmInfo instead of tCommon('addAnotherChild').
Added a hard rule to CLAUDE.md documenting the locale generation workflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add the "SUMMER EBT" logo above the landing page heading and the character/mascot icon above the child form heading, matching the Figma design frames. Assets exported from Figma MCP. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add review page clipboard icon (icon-review-card.svg) to match Figma - Fix button layout on ChildForm and ReviewPage to be side-by-side instead of full-width stacked (use USWDS flex utilities) - Create figma-verify skill for repeatable design verification - Document CO landing page content mismatch (spreadsheet fix needed) - Gitignore .claude-figma-verify/ and screenshots/ directories Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…spacing Set --font-urbanist CSS variable to Public Sans for the enrollment checker and add USWDS font-family-sans class to all headings for consistent typography without !important overrides. Shrink the memorable-date month select at mobile widths so Month/Day/Year fit on one row. Replace the usa-card wrapper on review cards with a faint outline border and heavy dividers between children to match the Figma design. Reduce icon-to-heading spacing on form and review pages. Update figma-verify skill with two-pass screenshot approach using Figma prototype URLs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…uild artifacts Matches Portal.Web gitignore rules (minus design token/SCSS rules). Removes tsconfig.tsbuildinfo from tracking and ignores .next/, next-env.d.ts, and other generated files. Includes Next.js auto-formatted tsconfig.json changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove from git tracking:
- .idea/ (15 JetBrains IDE config files) — developer-specific, not project config
- src/SEBT.EnrollmentChecker.Web/content/locales/ (28 generated locale JSONs)
- src/SEBT.EnrollmentChecker.Web/src/lib/generated-locale-resources.ts
- src/SEBT.EnrollmentChecker.Web/public/{css,fonts,img,js}/ (2601 USWDS assets)
These were committed before their .gitignore rules took effect. The EC Web
.gitignore already excludes them; the root .gitignore now uses a blanket
.idea/ rule instead of a single-file exclusion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
POST /api/enrollment/check— public, unauthenticated endpoint for checking children's Summer EBT enrollment statusIEnrollmentCheckServiceCheckId) per childOnRejectedhandlerPortalWebApplicationFactoryfor integration testing infrastructureKey files
EnrollmentCheckController, API request/response models, rate limit settingsCheckEnrollmentCommand,CheckEnrollmentCommandHandlerIEnrollmentCheckSubmissionLoggerEnrollmentCheckSubmissionLogger,DesignTimePortalDbContextFactoryIEnrollmentCheckServiceregistration inServiceCollectionPluginExtensionsDependencies
🤖 Generated with Claude Code