The top-level prune step deleted the whole db/ folder before the
second step meant to keep db/migrations under it ever ran, so no
deploy has actually shipped migrations - the remote apply step was
running runMigrations.vbs against an empty migrations folder and
silently reporting nothing pending.
Also adds scripts/run-migrations-remote(-apply).ps1, a lighter
migrations-only counterpart to deploy-iis.ps1 for catching a
production schema up without redeploying app code - used just now to
patch prod after this bug meant it never received prior migrations.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- scp/ssh now force a fallback to password auth so a missing/rejected
key fails with a real prompt instead of an opaque "Permission denied
(publickey)".
- Smoke test now checks each path against its expected status (/404 is
expected to 404) instead of treating any non-throwing response as a
pass, and surfaces the actual failure reason.
- The remote IIS server has the 64-bit Access Database Engine, unlike
the local dev machine, so its app pool stays 64-bit and migrations
run through the plain (64-bit) cscript.exe instead of SysWOW64.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Blue AV Envelope (Q3) no longer asks for a nonprofit authorization code
after confirming nonprofit status - it wasn't needed there. Ballot
Mailing Service (Q4) gains the same follow-up instead, with an "I don't
know my authorization code" checkbox that lets the applicant skip it.
Adds MailingNonprofitAuthCode and MailingNonprofitAuthCodeUnknown
columns to OrderDetails via migration, wired through the model,
repository, answers mapper, and confirmation email by hand rather than
via GenerateRepo.vbs, since regenerating would have dropped existing
fixups (leading-zero-preserving text fields, nullable boolean/date
guards) already baked into those files.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The success/error banners (e.g. "Check your email for a link") were
dismissing after only 3 seconds, too quick to read comfortably.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- .gitattributes + an explicit allow-list in build-release.ps1 assemble a
clean release tree (app/, core/, public/, scripts/, db/migrations only) -
anything not on the allow-list is deleted from the deploy, so a stray
file added later can't ship to production by accident.
- public/web.config.production.template holds the production appSettings
(DB path outside the deploy dir, Environment=Production, error logging on).
- deploy-iis.ps1 builds, zips, and scp's a release to the IIS host, then
runs deploy-iis-remote-apply.ps1 there over ssh to swap in the new files,
run migrations, and restart the site/app pool - the DB and error log live
outside the deploy directory so a redeploy never touches them.
- Removed deploy-iis-git.ps1 and migrate_isbusiness_to_households.vbs,
leftovers from a different template project that didn't apply here.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Schema changes go through db/migrations/; the live Access file itself
should never be committed or overwritten by a deploy. Its history was
purged from all commits/branches with git-filter-repo.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Implement Election Materials order-form revisions (docs/lucid *(2).pdf):
new "permanent ballot list" question, and a Yes/No/Unsure nonprofit-status
question now asked on both blue-envelope permit-ownership branches, with
a matching migration, model/repository regen, and validation updates.
- Box the /request-order form and heading in the site's form-panel style.
- Shrink the site footer.
- After request-order and order submission, redirect to / with a flash
message instead of re-rendering the form page inline.
- Skin the continuation and order-confirmation emails to match the site's
branding (logo, navy header/footer, purple accents) instead of plain
unstyled HTML.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Extract email sending into OrderMailer, answer-to-model mapping into
OrderDetailsAnswersMapper, label mapping into OrderDetailsLabels, and
generic dictionary-based field validation into core/lib.Validations.asp
(alongside a small lib.JsonResponse helper), replacing the private
helpers previously duplicated inline in OrderApiController and
RequestOrderController.
Extends the jurisdiction API cache to store JCode/Name pairs (not just
codes) and looks up the matching Name for an order's already-validated
JurisdictionNumber when rendering /order/continue. When a match is
found, the Municipality field is pre-filled and locked read-only;
otherwise it falls back to an empty, editable field so the user can
enter it manually.
- Blue AV Envelope: City of permit holder and Permit Number are now always
collected for an own-organization permit, regardless of nonprofit status -
a permit lookup using only the nonprofit authorization code doesn't work,
so the code is now additional info when nonprofit status is Yes, not a
replacement for city/permit number.
- Order confirmation email header simplified to "KCI Purple Envelope Order
Confirmation" text, dropping the site's PE logo mark and tagline.
- Replaced the IsValidJurisdictionNumber stub (previously always returned
true) with real validation against JurisdictionApiUrl, cached in
Application scope (JurisdictionCacheMinutes, default 60) since the
jurisdiction list is essentially static reference data. Falls back to
stale cached data on a refresh failure rather than blocking order
requests; fails open only when there's no cache at all.
Hit two Classic ASP gotchas along the way: Scripting.Dictionary can't be
stored in Application scope (ASP 0197, apartment-threaded COM object) -
cached a delimited string instead - and the codebase's generic aspJSON
parser took 43s to parse the ~1500-record API response, so switched to a
targeted regex extraction of just the JCode field (~1s).
Order form revision (docs/lucid "(1)" PDFs):
- Purple Envelope: reordered stock/permit questions, renamed postage-only to
state-permit-only, added colors question and blue-envelope-provider
cross-sell
- Blue Envelope: reworked permit flow with KCI-vs-own-organization
ownership and nonprofit-status branching
- Mailing Service: real per-piece pricing, new Presort Standard tier,
estimated-quantity question, fixed pickup-date list, removed the
ballot-sorting question
- Additional Items: added a special-requests field
- Added db/migrations/20260804153857_revise_order_details_columns.asp
(additive only - columns retired by the revision are left in place,
not dropped, since the table has real test data)
Tester feedback:
- Fixed "Spectrom" typo to "Spectrum" (value code + label + validation)
- Corrected First Class postage rate to $0.721/pc.
- Marked nearly every survey question required so SurveyJS blocks
page navigation on missing answers
Color picker for envelope colors:
- Replaced free-text color entry with a modal image picker sourced from
public/images/Purple_ballot_envelopes colors/*.bmp, converted to PNG
in public/images/purple-envelope-colors/ (23MB -> 245KB)
Cleanup pass:
- Removed the redundant "KCI's blue envelopes or another provider's"
question (redundant with the preceding yes/no)
- Removed the purple-envelope delivery-date picker in favor of a static
lead-time note
- Trimmed the Mailing Service page title
- Fixed the post-submission message to stop showing SurveyJS's default
"survey" wording
Response.ExpiresAbsolute was set to a far-future date at the same time as
Cache-Control: no-cache - contradictory directives that could let a cache
serve a stale copy of dynamic, session-tied content. Also, Response.AddHeader
"cache-control", ... doesn't affect the separate Response.CacheControl
intrinsic property (which defaults to "private" and was still being sent
regardless of AddHeader); set the property directly so the header is
actually correct on the wire.
Found while diagnosing a "Your form session expired" report that turned out
to be caused by something else (a server-side permissions issue), but this
is a real, independent correctness bug worth fixing regardless.
RouteKit Classic ASP MVC starter for the Purple Envelope election-materials
order site: request-order flow, token-based order continuation, SurveyJS
order-details form with server-side validation and a themed confirmation
email, plus the framework core, generators, and dev-only aspunit test harness.