WebCoPilot 2.0 is a ColdFusion-based CMS/marketplace platform originally built circa 2000. It powers a network of community shopping websites (think early Amazon marketplace meets local community directories). Each site has a storefront, event calendar, ad marketplace, and member portal. This specific installation runs mensprayerbreakfast.com — a men's prayer breakfast community site.
The system has been under active modernization since mid-2025, focusing on:
| File | What It Contains | Lines |
|---|---|---|
.github/copilot-instructions.md | THE BIBLE — every pattern, convention, table mapping, column rule, and CSS class. AI sessions are bound by these rules. | ~1,200 |
CLAUDE.md (site root) | Tech stack, DB credentials, key paths, widget system architecture, Google Maps API key | ~200 |
CustomTags/CLAUDE.md | CF Admin JDBC details, button standards, card header style, calendar form paths | ~100 |
_session_changelog.txt | Complete history of every session's changes — files modified, DB alterations, decisions made | 5,620 |
Read copilot-instructions.md first. Everything else is supplementary.
| Component | Version / Detail |
|---|---|
| App Server | ColdFusion 2023 Enterprise (Java 17+) on IIS 10 / Windows Server 2022 |
| Database | SQL Server 2016, host sql-2016, sa/Gfyse2013 |
| Primary DSN | mensprayerbreakfast_com → DB Mensprayerbreakfast_com |
| Secondary DSN | mensprayerbreakfast_com_2 → DB Mensprayerbreakfast_com_2 |
| Global DB | Global_Webstore (shared cross-site hub, 44 tables) |
| Billing DB | billing via DSN 3pb1 (site registry, DSN lookups) |
| SMTP | ntwrk.sendio.com — every cfmail MUST include server="ntwrk.sendio.com" |
| Front-End | Bootstrap 5.3.3, Bootstrap Icons 1.11.3, jQuery 3.7.1, DataTables 1.13.7 (all CDN) |
| Site Root | E:\m\mensprayerbreakfast.com\ |
| Custom Tags | C:\ColdFusion2023\cfusion\CustomTags\NewTags\ |
| Repo | Remote | Content |
|---|---|---|
E:\m\mensprayerbreakfast.com | WebCopilot2026/webcopilot (private) | Main site code |
C:\ColdFusion2023\cfusion\CustomTags | WebCopilot2026/WcpCustomTags (private) | Custom tags |
Import-Module SqlServer Invoke-Sqlcmd -ServerInstance "sql-2016" -Username "sa" -Password "Gfyse2013" ` -Database "Mensprayerbreakfast_com" -TrustServerCertificate -Query "SELECT ..."
Pages aren't flat HTML files — they're assembled from Layout Pages containing Widgets arranged in Columns.
Request → bsPage.cfm → queries Layout_Pages → calls <cf_Widget_Handler> per column
↓
queries Widgets table → loops each widget
↓
<cfswitch> on Widget_Name → renders "HTML", "Page", "DynamicInclude",
"Gallery", "Calendar", "AdSpace", etc. (100+ types)
Called as <cf_tagname> → maps to tagname.cfm in CustomTags\NewTags\. Key ones:
<cf_Widget_Handler> — renders all widgets<cf_Widget_Header> / <cf_Widget_Header2> — edit toolbar per widget<cf_status> — 4-letter PLHA status indicator (Private/Locked/Hidden/Active)<cf_ChangeLog> — audit trail for content edits<cf_CopyTheme> — clones color themes for new users<cf_mergeVars> — merge field variable replacementEvery table has its own "deleted" value:
Normal delete → UPDATE SET active_col = deleted_value (soft-delete) Un-delete → UPDATE SET active_col = 1 (restore) Hard delete → DELETE WHERE active_col = deleted_value (only removes soft-deleted records)
| Table | Column | Active | Deleted |
|---|---|---|---|
| Calendar | active | 1/NULL | 2 |
| Layout_Pages | active | 1 | 17 |
| Pages | IsActive | 1 | 2 |
| Sponsors | Is_Active | 1 | 2 |
| Colors | Active | 1 | 2 |
| Products | Discontinued | 0 | 2 |
| Orders | OrderStatus | (any) | 'Deleted' |
NEVER use BIT columns for active/status. Always TINYINT. BIT breaks soft-delete values >1 and Query-of-Query filtering.
Every admin search page follows this template:
Dark header bar (#1a1a2e) → Toolbar card → Results card with DataTable
DataTable column order (MANDATORY):
Checkbox | ...data columns... | Actions | Status/✓ | ID
Action buttons use .act pill classes (7 colors, text-only, 7pt font):
Every SQL parameter MUST use cfqueryparam. No raw variable interpolation in queries.
<!--- WRONG ---> WHERE ID = #url.ID# <!--- RIGHT ---> WHERE ID = <cfqueryparam value="#url.ID#" cfsqltype="cf_sql_integer">
For ORDER BY direction, use whitelist validation (can't parameterize):
<cfset _dir = ListFindNoCase("ASC,DESC", url.dir) ? url.dir : "ASC">
Most ownership uses Email_Username (string FK): Layout_Pages.Owner, Pages.Owner, Links.Owner, Colors.Owner, Calendar.Username, Widgets.Username
Products and Orders use Sponsor.ID (integer FK): Products.Owner, Orders.Owner
Workgroup = comma-delimited list of usernames a user can see/manage. Admin1 workgroup contains ALLBOX (sees everyone).
Email_Username is the internal FK (NOT changed). Alias is a display-friendly identifier shown in URLs and admin columns instead of the raw email.
URL resolution: if url.owner matches an Alias, it's translated to Email_Username before any query runs.
<cflayout> / <cflayoutarea> → BS5 nav-pills + tab-pane<cftooltip> → title attribute (~20 files)<cfajaximport> removed (~8 files)<cfdiv> → <div>ColdFusion.Window.create → BS5 modalColdFusion.Layout.selectTab → removed (BS5 handles tabs natively)secure.ntwrk.net references → #cartpath# (~20 files)The file manager now uses a deferred commit workflow:
NEW badge.global_Images, soft-deletes orphaned records, rebuilds Gallery_ImageList.Global_Subscribers_search.cfm — DELETE targets wrong table| Area | Entry Point | Key Files |
|---|---|---|
| Admin panel | /admin.cfm | BS5 sidebar iframe layout |
| Public pages | /bsPage.cfm?page=PageName | Widget-based rendering |
| Member portal | /members/index.cfm | Fusebox routing via fbx_switch.cfm |
| File Manager | /members/dirlist.cfm?subdir=galleries | Gallery file management |
| Gallery admin | /Modules/Galleries/Gallery_Search.cfm | Gallery CRUD + image management |
| Product admin | /Modules/WebStore/Product_Search.cfm | Product catalog management |
| Order admin | /Modules/WebStore/Orders_Search.cfm | Order management |
| Calendar | /files/calendar/index.cfm | Event management |
| Config vars | /Modules/Configuration/index.cfm | CustomVars CRUD |
Before writing any code, verify:
cfqueryparam on every SQL parameter## for literal # inside <cfoutput> (hex colors, etc.)url.ID, form.Name, Client.Email_Username.act pill buttons for table row actions (7 classes by task type, not label)server="ntwrk.sendio.com" on every <cfmail> tagEmail column — it's Email_Username (login AND email)_OLD.cfm) before rewriting any file
The copilot-instructions.md file is the single source of truth. Updated every session.
Check _session_changelog.txt for decision history.
Welcome aboard, Ernie. 🛠️