# AGENTS.md — Galactic Conquest Classic (GCC)

> Read this file before making any changes. It tells you what the project is, how to find things, and what rules to follow.

## Identity

- **What:** Browser-based multiplayer persistent-universe strategy game (text/HTML MMORPG)
- **Stack:** ColdFusion (CF5 syntax on Lucee engine) · MySQL 8 (`gcc` schema) · Apache 2 · server-rendered HTML · jQuery-era JS
- **Version:** 2.77
- **Owner:** Wolfren Industries
- **Servers:** Real-Time (slot 1, 1 turn/8s) and Turn-Based (slot 2, 1 turn/2.5min). Slots 3–5 are dead code.

## Quick-Start Decision Tree

```
Need to change game behavior for a logged-in player?
  → f_com_*.cfm (player commands) or f_fed_*.cfm (federation)

Need to change a public/unauthenticated page?
  → p_*.cfm at root

Need to change shared logic used across features?
  → s_*.cfm at root, or Modules/Functions/Functions.cfm

Need to change the page layout, nav, or frame?
  → i_f_800.cfm (game frame), i_*.cfm (partials)

Need to change background/scheduled jobs?
  → Z_*.cfm at root

Need to change admin panel?
  → edmin/ directory

Need to change app config, datasources, or session settings?
  → Application.cfc

Need to trace a request end-to-end?
  → Start at i.cfm, follow url.f or url.p routing
```

## Request Lifecycle

All HTTP requests enter through `i.cfm`:

```
i.cfm
├─ Loads s_loadvar.cfm (basic variables)
├─ Loads Modules/Functions/Functions.cfm
├─ IF session.userid exists AND url.f present:
│   ├─ s_loadsystem.cfm (app-scope cached data)
│   ├─ i_f_800.cfm (game page frame: nav, layout, chat)
│   │   └─ Includes f_<url.f>.cfm OR Modules/Pages/<url.f>.cfm
│   └─ Renders full game page
├─ ELSE (unauthenticated):
│   ├─ i_p.cfm (public frame)
│   │   └─ Includes p_<url.p>.cfm
│   └─ Renders public page
```

**Key variables:**
- `url.f` — routes to feature files (authenticated)
- `url.p` — routes to public page files (unauthenticated)
- `session.userid` — current player ID
- `session.server` — active server slot (1 or 2)

## File Naming Map

| Prefix | Role | Count | Location |
|--------|------|-------|----------|
| `p_*.cfm` | Public pages (login, signup, landing) | ~33 | root |
| `f_com_*.cfm` | Player game commands (attack, build, research) | ~75 | root |
| `f_fed_*.cfm` | Federation features | 11 | root |
| `f_*.cfm` (other) | Misc features (PM, rank, etc.) | ~15 | root |
| `s_*.cfm` | System utilities, shared logic, value lookups | ~65 | root |
| `i_*.cfm` | Includes/partials (layout, header, nav) | ~10 | root |
| `Z_*.cfm` | Background/scheduled processes | 12 | root |
| `*.cfc` | Components (Application config, controllers) | few | root + Modules/ |

## Directory Map

```
/opt/gcc-dev/app/
├── Application.cfc            # Config: datasources, sessions, server slots, PayPal
├── i.cfm                      # Main router — ALL requests enter here
├── i_f_800.cfm                # Authenticated game page frame (nav + layout + chat)
├── i_p.cfm                    # Public page frame
│
├── f_com_*.cfm                # ~75 player command files
├── f_fed_*.cfm                # 11 federation files
├── s_*.cfm                    # ~65 system/utility files
├── p_*.cfm                    # ~33 public page files
├── Z_*.cfm                    # 12 background process files
│
├── Modules/
│   ├── Controllers/           # CFC controllers
│   │   ├── Projects/          # Project system (1.cfc–10.cfc, Update.cfc, Activate.cfc)
│   │   └── HT/Projects/      # High-tech project variants
│   ├── Pages/                 # View templates loaded via url.f routing
│   │   └── Projects/          # Project-specific views
│   ├── Functions/
│   │   └── Functions.cfm      # Shared utility functions (validateURL, formValidate, hackCheck)
│   ├── NPC/                   # NPC generation and AI
│   │   └── Fleet/             # NPC fleet logic
│   └── Ships/
│       └── Builder.cfm        # Ship construction logic
│
├── edmin/                     # Admin panel (~168 files)
│   ├── Application.cfc        # Admin-specific config
│   ├── p_login.cfm            # Admin login
│   └── f_admin_*.cfm          # Admin action files
│
├── forum2/                    # Active forum system (~25 files)
├── forum/                     # Legacy forum (dead — superseded by forum2/)
├── l/                         # Localized templates (~50 files mirror root structure)
├── text/                      # In-game manual pages (manual_*.cfm)
├── help/                      # Help documentation (HTML)
├── Stats/                     # Statistics/reporting pages
├── JS/                        # JavaScript files (~84)
├── CSS/                       # Stylesheets (~59)
└── i/                         # Image assets
```

## Core Game Concepts

Agents editing feature files need to understand these:

**Turns** — The universal action currency. Players spend turns to do everything (build, research, attack, explore, generate income). Turns accumulate automatically via `z_endturn.cfm` up to a cap. Turn spending logic lives in `s_endturn.cfm`.

**Colonies** — Planets a player owns. Each has population, buildings, ore, food. Managed via `f_com_col*.cfm`. Colony state is frequently cached in application scope.

**Ships** — Built at colonies, organized into fleets. Ship types and classes loaded from DB into app scope by `s_loadsystem.cfm`. Building logic in `Modules/Ships/Builder.cfm` and `f_com_ship*.cfm`.

**Research** — Tech tree loaded into `application` scope from `restree` table. Research pages: `f_com_research*.cfm`, `f_com_rtree*.cfm`.

**Combat** — Attack flow spans multiple files: `f_com_attack*.cfm` (UI/initiation) → `s_com_attack*.cfm` (calculation/resolution).

**Federations** — Player alliances. All fed logic in `f_fed_*.cfm`.

**Market** — Player-to-player trading. `f_com_market*.cfm` (UI) and `s_com_market*.cfm` (logic).

**Projects** — Long-running constructions. Modularized in `Modules/Controllers/Projects/` and `Modules/Pages/Projects/`.

**NPC System** — AI-controlled entities. `Modules/NPC/` handles generation and fleet behavior.

## Key Files Reference

| File | Why It Matters |
|------|---------------|
| `Application.cfc` | All config: datasources, sessions, server slots, env flags. Read first for environment issues. |
| `i.cfm` | Main router. Trace any request starting here. |
| `i_f_800.cfm` | Game page frame. Contains nav, layout, chat, resource display, turn counter. |
| `s_loadsystem.cfm` | Loads all application-scope cached data (races, ships, research, planets, etc.) on first request. |
| `s_loadvar.cfm` | Basic variable initialization, loaded before s_loadsystem. |
| `Modules/Functions/Functions.cfm` | Shared functions: `validateURL()`, `formValidate()`, `hackCheck()`, `reverseIPDisplay()`. |
| `s_endturn.cfm` | Turn spending logic (called per player action). |
| `z_endturn.cfm` | Turn generation (scheduled background process). |
| `Z_Hourly_Processes.cfm` | Master hourly job dispatcher. |
| `s_error2.cfm` | Error notification (sends email). |
| `s_loadbar.cfm` | Left navigation bar generation. |
| `theme.css` | Theme tokens (colors, fonts, radii, shadows) + modern component classes for Nebula/Daylight. Classic kept legacy. |
| `f_option_screen.cfm` | Theme picker UI. Writes the theme to the client record. |

## Critical Rules

### 1. Security Guard — `ihasrunflag`

Most include files check `ihasrunflag` to prevent direct URL access. If you create a new `.cfm` that should only be included (not hit directly), add this at the top:

```cfml
<cfif parameterExists(ihasrunflag) IS "NO"><cfabort></cfif>
```

### 2. Database — Only Use `gcc`

The `gcc` and `gcc_log` datasources are the only ones that matter. Other datasources (`ucc`, `ucc_log`, `gcs`, `gcs_log`) are legacy and should not be used for new code.

### 3. SQL — Parameterize Tainted Values, Not SQL Structure

The codebase has a legacy pattern of raw variable interpolation in queries. The default rule is still: **parameterize user-controlled values and anything that is not provably constrained server-side**.

For new queries, and for queries you are already editing, prefer CFScript `Query` objects with named params:

```cfml
<cfscript>
Qry = new Query();
Qry.setDatasource(application.DS);
Qry.setSQL("INSERT INTO project_user
			(userid, project, credit, turn, finishflag)
			VALUES
			(:userid, :projectid, 0, 0, 0)
			ON DUPLICATE KEY
			UPDATE userid = userid");
Qry.addParam(name="userid", value=session.userid, cfsqltype="integer");
Qry.addParam(name="projectid", value=requestedProjectId, cfsqltype="integer");
QryFetch = Qry.execute();
</cfscript>
```

Use named arguments with `addParam(name, value, cfsqltype, scale, null, maxlength)`. Lucee may not bind SQL params correctly with positional arguments. Use these short `cfsqltype` names:

| Full Name | Short Name |
|-----------|------------|
| `cf_sql_integer` | `integer` |
| `cf_sql_varchar` | `varchar` |
| `cf_sql_char` | `char` |
| `cf_sql_timestamp` | `timestamp` |
| `cf_sql_date` | `date` |
| `cf_sql_time` | `time` |
| `cf_sql_bigint` | `bigint` |
| `cf_sql_decimal` | `decimal` |
| `cf_sql_double` | `double` |
| `cf_sql_float` | `float` |
| `cf_sql_numeric` | `numeric` |
| `cf_sql_bit` | `bit` |
| `cf_sql_boolean` | `boolean` |

Tag-based legacy queries may still use `cfqueryparam` when you are not converting the whole query:

```cfml
<!--- WRONG (legacy pattern found ~700 times) --->
WHERE userid = #session.userid# AND name = '#form.name#'

<!--- RIGHT --->
WHERE userid = <cfqueryparam value="#session.userid#" cfsqltype="cf_sql_integer">
AND   name   = <cfqueryparam value="#form.name#"      cfsqltype="cf_sql_varchar">
```

Use query parameters for:

- All `form.*` input unless the value was explicitly normalized immediately above and reduced to a tight primitive such as digits-only.
- `url.*`, `cgi.*`, `cookie.*`, `client.*`, and request values coming from JS/AJAX, even if they "should" be numeric.
- Any string that can contain player-entered, admin-entered, or database-stored content.
- `IN (...)` lists built from request data. Use a named param per value, or `cfqueryparam list="true"` only when staying in tag-based legacy code.
- Dates, timestamps, booleans, and numerics when the value came from outside the current template.

Interpolation without query parameters is acceptable only when all of the following are true:

- The value is not user-controlled at that point in the request.
- The value has been reduced to a narrow primitive or explicit allowlist.
- It is being used as a value, not as SQL structure.
- Adding `cfqueryparam` would be pure churn in untouched legacy code rather than a meaningful safety improvement.

Examples of acceptable narrow cases:

- Route/include selectors such as `url.p`, `url.f`, and `url.a` after the top-level `ReReplace(...,"[^0-9a-zA-Z_]","","ALL")` filter. Those are file-routing tokens, not freeform text.
- Small allowlisted numeric selectors such as a race ID that is immediately constrained to a known set before use in non-SQL logic.
- Server-owned integers such as `session.userid` or `session.server` in unchanged legacy queries, though parameterizing them is still preferred when you are already modifying that query.

Do not treat sanitization as a blanket exemption:

- `validateURL()` is a helper, not a global enforcement point.
- The top-layer `url.p` / `url.f` cleanup only proves "alphanumeric/underscore", not business validity.
- `formValidate()` strips characters but does not replace query parameters, output encoding, or allowlist checks.
- SQL identifiers, column names, sort directions, and table names cannot be safely parameterized; validate those with an explicit allowlist instead.

### 4. Output Encoding — Encode User Content

The codebase currently has zero output encoding. **All new or modified output of user-supplied data must be encoded:**

```cfml
<!--- HTML body text --->
#encodeForHTML(playerName)#

<!--- HTML attribute --->
value="#encodeForHTMLAttribute(val)#"

<!--- JavaScript string --->
var x = '#encodeForJavaScript(val)#';

<!--- URL parameter --->
?name=#encodeForURL(val)#
```

### 5. No `evaluate()` — Use Struct Bracket Notation

```cfml
<!--- WRONG --->
#evaluate("application.server#session.server#_turnmin")#

<!--- RIGHT --->
#application["server#session.server#_turnmin"]#
```

### 6. Application Scope

`s_loadsystem.cfm` caches heavily into `application.*`. Check existing application variables before adding DB queries — the data may already be loaded. Key cached data: ship classes, research tree, race data, planet types, user names, federation names, navigation bars.

### 7. Server Slots

Only slots 1 (Real-Time) and 2 (Turn-Based) are active. `this.ServerMax = 5` in Application.cfc is legacy. Code referencing servers 3–5 is dead.

## Frontend / Theming

Three themes are selected via `[data-theme]` on `<body>`. Preference is stored on the client record and chosen at `f=option_screen`.

| Theme | Notes |
|-------|-------|
| `nebula` (default) | Modern dark — navy surfaces, amber accents, Fraunces + IBM Plex fonts. |
| `classic` | **Preserves the legacy look exactly.** Crimson/black chrome, Arial body, starfield bg. Do not modernize. |
| `daylight` | High-contrast light mode — indigo accents on white. |

All tokens (colors, fonts, radii, shadows, motion) live in `theme.css` as CSS custom properties scoped per `body[data-theme]`. Use tokens (`var(--bg-surface)`, `var(--accent)`, `var(--accent-good)`, `var(--accent-hot)`, `var(--font-display)`, `var(--font-mono)`, `var(--radius-md)`, etc.) — never hardcode colors or fonts in new code.

### 1. Classic is sacred

Scope all new modern styling to the two modern themes:

```css
body[data-theme="nebula"] .thing,
body[data-theme="daylight"] .thing { ... }
```

Never touch Classic's presentation except for genuine bug fixes or shared-layout correctness. The whole reason Classic exists is so long-time players don't get a changed UI.

### 2. Dual-branch page templates for redesigns

When a page needs a modern overhaul, branch the template on theme. Keep Classic's legacy markup intact and render new markup for the modern branch. Reference implementation: `f_com_income.cfm`.

```cfml
<cfset isClassicTheme = lCase(trim(client.theme & "")) EQ "classic">
<cfif isClassicTheme>
  <!--- legacy markup, untouched --->
<cfelse>
  <!--- modern gc-* component layout --->
</cfif>
```

### 3. Mobile-first, one-viewport target

Every new modern layout must fit a mobile viewport without scrolling. Rules:

- Write base CSS for narrow screens; widen with `@media (min-width: 520px|640px|992px)`.
- Stack side-by-side panels below 640px.
- Cut empty cells, blank rows, and decorative section spacers.
- Body 13px. Numerics in `var(--font-mono)` with `font-variant-numeric: tabular-nums`. Hero figures in `var(--font-display)`. Section labels in 10–11px uppercase mono.
- Never emit empty `<td>` padders. Use CSS grid or `<dl>` so cells appear only when they have content.
- Prefer a single dashed divider over a thick border plus 10px of padding.

### 4. Reusable modern components

Patterns established on `f_com_income.cfm`, defined in `theme.css` under the `INCOME / UPKEEP LEDGER` block. Reuse or extend rather than inventing per-page markup.

- **Hero stat cards** — `.gc-income-hero` > `.gc-income-hero__card` with `--primary` / `--positive` / `--negative` modifiers. At-a-glance metrics with signed, color-coded values and an accent edge strip.
- **Credit/debit sections** — `.gc-income-section` with `--credits` (green top-edge) / `--debits` (red top-edge) modifier, and `__head` / `__title` / `__total` children.
- **Line items** — `.gc-ledger` > `.gc-ledger__row` with `__label` + `__actual` grid, optional `__calc` muted subline for `base × mod%`, and `__empty` for placeholder text.

Class names are currently income-scoped. When redesigning a non-financial page with the same shape, treat them as a credit/debit/ledger pattern rather than literally income-only. If a truly generic need emerges, extract aliases (`.gc-hero`, `.gc-card`, `.gc-section`) before shipping.

### 5. Where styles live

- **Shared modern styling** → `theme.css`, appended at the bottom grouped by feature with a comment header.
- **Classic-only fixes** → `theme.css` under a `body[data-theme="classic"]` scope, only if required.
- **Page-specific one-offs** → avoid; prefer adding a reusable class to `theme.css`.
- **Legacy stylesheets are dead** → `Style.css`, `RenStyle.css`, `Foundation_Style.css`, and most files in `CSS/` are being deprecated. Don't add new rules to them.

## Feature Area Quick Reference

| Area | UI Files | Logic Files | DB Tables (likely) |
|------|----------|-------------|--------------------|
| Authentication | `p_login.cfm`, `p_signup.cfm` | — | `user` |
| Turns | — | `s_endturn.cfm`, `z_endturn.cfm`, `Z_Hourly_Processes.cfm` | `user` (turn count) |
| Colonies | `f_com_col*.cfm` | `s_com_col_*.cfm` | `colony`, `building` |
| Ships | `f_com_ship*.cfm` | `Modules/Ships/Builder.cfm` | `ship`, `shipclass` |
| Research | `f_com_research*.cfm`, `f_com_rtree*.cfm` | `s_com_research_*.cfm` | `restree`, `user_research` |
| Combat | `f_com_attack*.cfm` | `s_com_attack*.cfm` | `attack`, `ship` |
| Exploration | `f_com_explore*.cfm` | `s_explore_*.cfm` | `system`, `planet` |
| Federations | `f_fed_*.cfm` | — | `federation`, `fed_member` |
| Market | `f_com_market*.cfm` | `s_com_market_*.cfm` | `market` |
| Projects | `f_com_project*.cfm` | `Modules/Controllers/Projects/` | `project` |
| NPC | — | `Modules/NPC/` | `npc`, `npc_fleet` |
| Private Messages | `f_pm.cfm` | — | `pm` |
| Sector Messages | `f_com_msgsector*.cfm` | — | `msg_sector` |
| Forums | `forum2/` | `forum2/s_*.cfm` | `forum_*` |
| Admin | `edmin/` | `edmin/f_admin_*.cfm` | various |
| Donations/Store | `f_com_donate*.cfm`, `f_com_cart*.cfm` | — | `donation`, `cart` |
| Background Jobs | — | `Z_*.cfm` | various |

## Localization

The `l/` directory mirrors the root file structure with localized versions. If you modify text in a root template, check if `l/<same_filename>` exists and needs a corresponding update.

## Admin Panel

The `edmin/` directory is a semi-independent sub-application with its own `Application.cfc`. Admin files follow the same prefix convention (`p_` for pages, `f_admin_` for actions, `s_admin_` for utilities). Admin access is gated by a user-record flag. Reference files: `edmin/_ids.txt` files contain ID-to-name mappings for projects and research items.

## Background Processes

| File | Schedule | Purpose |
|------|----------|---------|
| `Z_Hourly_Processes.cfm` | Hourly | Master dispatcher — runs sub-jobs |
| `z_endturn.cfm` | Every 8s (RT) / 2.5min (TB) | Turn generation for all players |
| `Z_Upkeep_Calc.cfm` | Periodic | Ship upkeep cost calculation |
| `Z_UpdateDB*.cfm` (1–5) | As needed | Database maintenance/migrations |
| `Z_Ships.cfm` | Periodic | Ship-related batch processing |
| `Z_Ajax_Chat.cfm` | Frequent | Chat message polling |

These run via server-side scheduler, not user requests. They currently have empty `cfcatch` blocks — errors are silently swallowed.

## Known Hazards

1. **~700 SQL injection points** — raw `#variable#` in queries across 200+ files. Some routes and helper inputs are partially sanitized, but that is not a substitute for query parameterization or explicit allowlists.
2. **Zero XSS encoding** — no `encodeForHTML()` anywhere. User content renders as raw HTML.
3. **Plaintext passwords** — login files compare plaintext. Migration to bcrypt is planned.
4. **Partial / inconsistent request sanitization** — `i.cfm` contains ad hoc query-string filtering and route cleanup, and `Functions.cfm` has `validateURL()`, `formValidate()`, and `hackCheck()` helpers, but enforcement is inconsistent. `validateURL()` and `hackCheck()` are not centrally called, and the `i.cfm` hack-detection branch is disabled by `|| 1 == 2`.
5. **`evaluate()` usage** — `i_f_800.cfm` uses `evaluate()` for dynamic variable access. Replace with struct bracket notation.
6. **Hardcoded user bypasses** — `p_login.cfm` lines 89–93 have backdoors for specific user IDs.
7. **Error info disclosure** — `Application.cfc` `onError` exposes file paths and stack traces to browser.
8. **PayPal credentials in source** — `Application.cfc` lines 194–206 have hardcoded client ID and secret.

## Related Documentation

| File | Contents |
|------|----------|
| `project_overview.md` | Detailed project overview, architecture, full file naming conventions |
| `modernization_plan.md` | Phased plan for security fixes, reliability, legacy cleanup, and frontend modernization |
| `README.md` | Brief repo description |
| `help/` | In-game help pages (HTML) |
| `text/manual_*.cfm` | In-game manual content |
