All new ASP Classic / VB6 web applications in this workspace are built on the RouteKit Classic ASP MVC framework (source: https://onefortheroadgit.sytes.net/dcovington/asp-classic-unified-framework.git). Do not hand-roll a routing/DAL/error-handling scheme when this framework already provides one — use it, and only extend it inside app/ (never modify core/).
public/ # IIS site root — Default.asp (front controller), web.config
core/ # Framework internals — do not modify
autoload_core.asp # loads all core libraries
router.wsc # route matching
mvc.asp # MVC_Dispatcher_Class — resolves route, validates controller/action against the whitelist, dispatches
databaseConnection.asp # DatabaseConnection_Class — ADODB.Connection factory (Access/SQL Server/ODBC)
lib.DAL.asp # DAL() singleton — Database_Class initialized from GetAppSetting("ConnectionString")
lib.ErrorHandler.asp # ErrorHandler_Class — dev vs prod error display + flat-file logging
lib.Migrations.asp # Migrator_Class — schema_migrations table, Up/Down migrations, transactional
lib.ControllerRegistry.asp # controller/action name-format + whitelist validation
helpers.asp # GetAppSetting(), QuoteValue, FormatDateForSql, etc.
app/
controllers/ # one *_Class per controller + autoload_controllers.asp
views/<Controller>/ # one .asp view per action; app/views/shared/ for header/footer
models/ # generated POBOs
repositories/ # generated repository classes
db/
migrations/ # timestamped *.asp migration files (YYYYMMDDHHMMSS_description.asp)
webdata.accdb # the Access database (dev default)
scripts/ # code generators, run via cscript
tests/ # dev-only aspunit harness — separate IIS app, sibling to public/
cscript //nologo scripts\generateMigration.vbs create_my_table → edit the generated db/migrations/<ts>_create_my_table.asp, implementing Migration_Up(migration) / Migration_Down(migration) using MigrationContext_Class helpers (CreateTable, AddColumn, DropColumn, CreateIndex, ExecuteSQL).cscript //nologo scripts\GenerateRepo.vbs /table:my_table /pk:id → move generated POBO/repository into app/models/ and app/repositories/.cscript //nologo scripts\generateController.vbs MyController "Index;Show(id);Create;Store" → move into app/controllers/.core/lib.ControllerRegistry.asp, include from app/controllers/autoload_controllers.asp, add routes in public/Default.asp, add views under app/views/MyController/.cscript //nologo scripts\runMigrations.vbs status (and up) to apply pending migrations — never hand-edit webdata.accdb's schema outside a migration file.ADODB.Connection directly in a controller/view. Use DAL() (core/lib.DAL.asp), which wraps DatabaseConnection() (core/databaseConnection.asp) and is initialized once per request from GetAppSetting("ConnectionString") in public/web.config.DAL__Singleton and DatabaseConnection__Singleton are page-scope Dim variables, not Application-scoped. Never cache a DAL()/connection reference in Session or Application scope; each request must acquire and release its own.QuoteValue() (core/helpers.asp) for any value that must be inlined into dynamic SQL, and FormatDateForSql() for date literals.Migrator_Class (core/lib.Migrations.asp) only, run via scripts/runMigrations.vbs. ApplyMigration/RollbackMigration already wrap each migration in BeginTransaction/CommitTransaction/RollbackTransaction.This app is a web app where multiple ASP sessions read/write the same .accdb concurrently (see .devfoundry/rules/database-sql.md for the general rule). In this framework specifically:
DAL()/Migrator_Class-style BeginTransaction/CommitTransaction/RollbackTransaction so partial writes can't leave the .accdb in a locked, half-written state.runMigrations.vbs (structural changes) during a maintenance window with no concurrent user traffic — the migration's own transaction protects the schema, but table-locking under structural DDL can still starve concurrent user requests.ErrorHandler_Class (core/lib.ErrorHandler.asp) — ErrorHandler().HandleError(context, Err) or ErrorHandler().CheckAndHandle(context). It already branches on GetAppSetting("Environment") (detailed HTML in Development, generic message in Production).public/web.config appSettings: EnableErrorLogging (true/false) and ErrorLogPath (absolute path). Set both per environment in .devfoundry/references/environments.md once known for this project — do not invent a different logging mechanism.core/mvc.asp's dispatcher already wraps controller-action execution and calls its own dispatch-error handler; new controllers do not need to duplicate top-level On Error Resume Next around the whole action unless doing something the dispatcher doesn't cover.aspunit harness under tests/, run as a separate IIS application (sibling to public/, parent paths enabled). See TESTING.md in the framework repo for full setup.tests/unit/ (deterministic helpers/registry), tests/component/ (controller/object with controlled setup), tests/integration/ (router/dispatch, config, rendered-output smoke tests).../aspunit/Lib/ASPUnit.asp and ../bootstrap.asp, registers a module via ASPUnit.AddModule(...), calls ASPUnit.Run(), and must be added to tests/test-manifest.asp (manifest is manual, no auto-discovery).run-all.asp inside the tests/ IIS app) or tests\run-tests.cmd. Because a real test harness exists, the TDD rule in .devfoundry/rules/general.md applies literally here — write the failing aspunit test first, confirm it fails, then implement.ASPUnitRunner.asp's client-side code fetches each manifest page as <page>?task=test via jQuery); a non-interactive/agent QA check cannot just curl run-all.asp and expect aggregate results (it returns {"testCount":0,...} with no JS engine). Hit each page in tests/test-manifest.asp directly with ?task=test instead — each returns raw per-suite JSON (testCount, passCount, modules[].tests[]).<site> in applicationhost.config when launched without /site:, even if every site has serverAutoStart="true". Running the production (public/) and test (tests/) sites simultaneously requires two iisexpress.exe processes, each with an explicit /site:"<name>" and ASPC_STARTER_ROOT set in its environment — see run_site.cmd at the repo root (confirmed via SPEC-004).Before trusting a “generic”/domain-agnostic claim about a freshly cloned copy of this framework (e.g. a commit message claiming domain-specific code was removed), check for leftover artifacts rather than assuming the claim is accurate:
db/webdata.accdb's actual tables (e.g. ADODB.Connection.OpenSchema(20)) and compare against what db/migrations/*.asp and any one-off scripts/*.vbs migration/deploy scripts reference — a stray migration or script naming tables the .accdb doesn't actually have is a sign of incomplete cleanup from a prior project, not something to vendor as-is.scripts/ for deploy or one-off migration scripts hardcoded to a different project's name (SPEC-004 found deploy-iis-git.ps1 and migrate_isbusiness_to_households.vbs left over from an unrelated “asp-territory” project) and exclude them from vendoring.public/web.config <appSettings> (ConnectionString, Environment, EnableErrorLogging, ErrorLogPath, plus UI/cache settings) and are read via GetAppSetting(key) (core/helpers.asp), which caches per-key in Application scope after first read.GetAppSetting.Powered by TurnKey Linux.