00 — Context
Problem statement
Section titled “Problem statement”Adventive’s internal administrative interface is a single legacy application (adventive-admin, BitBucket-hosted, version 3.3.9) that handles two distinct responsibility domains:
- Customer service-level management — operator tooling for managing customer accounts, tiers, entitlements, and configuration.
- Billing — invoice generation, line-item rollup, Stripe invoice creation via API, custom invoice PDF rendering, and email delivery via Mailgun.
The application mixes API logic with presentation in a single codebase, does not reflect current Adventive brand guidelines, and has accumulated pain points typical of a long-lived internal tool. It is also the coupling point for a custom billing flow that the Stripe Billing Transition project will evaluate for replacement.
Repo analysis (April 2026) surfaced two findings that raise the urgency of migration beyond architectural debt alone:
- Production AWS and Bitbucket credentials are hardcoded in source (
application/config/adventive.php) — a live secret-exposure risk in every clone and CI artifact. - CSRF protection is globally disabled and Duo 2FA is currently bypassed — the admin’s only active access control is JumpCloud username/password.
Business motivation
Section titled “Business motivation”- Architectural debt: the admin is the last major internal surface not yet aligned with Adventive’s API-first / Cloudflare Workers direction (Public API migration landed 2026-04; Cloudflare Tunnel landed prior).
- Secret exposure: AWS access keys, S3 secrets, and Bitbucket OAuth credentials are committed to source for all three environments. Remediation is blocked until secrets are moved to a managed store; this migration provides the natural forcing function.
- Security posture: CSRF disabled (
config.php:320), Duo 2FA bypassed (latest auth commit), payment links secured only by MD5 hash (Billing.php:561). Cloudflare Access restores edge-enforced MFA and eliminates application-managed auth entirely. - Presentation coupling: mixing presentation and API logic makes it hard to evolve either independently; a future mobile or partner-facing admin surface is effectively blocked.
- Brand drift: the visual layer predates the current brand system and reads as legacy to internal users.
- Billing entanglement: the admin owns both the billing UI and meaningful billing business logic. That logic is the scope-of-analysis input for the sibling Stripe Billing Transition project — separating presentation from API is a prerequisite for cleanly migrating billing.
- Dependency risk:
phpoffice/phpexcel1.7.9 (archived 2019, no security patches) is installed alongside its successorphpspreadsheet. CodeIgniter 3.1.* receives no active maintenance.
-
In scope:
- Architecture audit of
adventive-admin(routes, data model, integrations, auth). ✓ Complete — see §01. - Serverless viability assessment for the API layer (Cloudflare Workers fit). ✓ Complete — see §01.
- Target architecture: separate API Worker + Cloudflare Pages SPA. ✓ Decided.
- UI refresh aligned with current Adventive brand guidelines.
- Auth/authz model: Cloudflare Access for operator identity, application RBAC for authorization. ✓ Decided.
- Migration plan with phased cutover and rollback. ✓ See §02.
- Documentation: full planning deliverable set → PDF → Claude Code handoff package.
- Architecture audit of
-
Out of scope:
- Billing business logic redesign — owned by
../Stripe Billing Transition/. This project defines the seam; that project decides what lives on which side of it. - Public-facing customer UI.
- Migration of the underlying customer / account / billing data stores (unless assessment surfaces a forced dependency — it did not).
- Partner-specific scheduled reports (
Reporting.php, 25 methods) — deferred; evaluated for a dedicated analytics service in Phase 4.
- Billing business logic redesign — owned by
-
Deferred:
- Mobile or offline operator access.
- External partner/reseller admin surfaces.
- Feature additions beyond parity with the current admin.
- Directory provider choice for Cloudflare Access (JumpCloud vs. Google Workspace) — deferred per ADR.
Success criteria
Section titled “Success criteria”- Written and signed architecture plan matching the Adventive Engineering PDF standard. ✓ This document.
- Clear API contract definition (OpenAPI via
@hono/zod-openapi) that billing, service-level management, and any future consumer can build against. - Presentation layer demonstrably decoupled — can be rebuilt or replaced without touching the API.
- Brand-guideline review sign-off on the new UI direction (reference: brandguide.adventive.com/dashboard).
- Cutover plan with rollback path and defined success metrics (operator task completion time, error rate parity or better).
- Implementation handoff package ready for Claude Code (CLAUDE.md, PLAN.md, kickoff doc — matching Public API pattern).
- Production secrets removed from source and moved to AWS Secrets Manager or Cloudflare secrets before implementation begins.
Stakeholders
Section titled “Stakeholders”| Role | Name | Interest |
|---|---|---|
| Owner | Jeffrey Lambert | Architecture, plan quality, delivery |
| Approver — UI | Jeffrey Lambert | Brand alignment, UX sign-off |
| Approver — API | Patrick | API contract, backend architecture sign-off |
| Approver — Billing UI | Jeffrey + Patrick | Joint sign-off on billing surface area of the admin |
| Informed | Adventive operations team (~10 operators) | End users of the new admin |
Operator population and RBAC tiers
Section titled “Operator population and RBAC tiers”~10 operators total, across three permission tiers:
| Tier | Count | Capabilities |
|---|---|---|
| Super-admin | 2 | All functionality across customer, service-level, billing, and tooling domains |
| Billing | TBD | Billing-scoped operations (invoices, payments, managed services, reports). Read access to accounts. |
| Read-only | TBD | Read access across all surfaces, no mutations |
The two super-admins are the only tier with authority to destructive / cross-domain operations. Billing-tier operators can read all customer context but only write billing-domain records.
Design reference
Section titled “Design reference”Visual and interaction language target: https://brandguide.adventive.com/dashboard — the Adventive brand-guide dashboard concept. “Similar in design, refined for utility.” Not a literal reskin; the admin’s job is operator efficiency first.
Project sequencing
Section titled “Project sequencing”This project runs first, ahead of the Stripe Billing Transition migration phase. Rationale:
- The presentation/API separation is a prerequisite for cleanly migrating billing — you can’t cleanly replace a subsystem that shares a codebase with its UI.
- The new admin will surface whatever billing decision gets made downstream (custom, Stripe-native, or hybrid), so it needs to be designed to tolerate that outcome without rework.
- Admin-first also front-loads the architectural work that the billing project will consume.
- The secret-exposure and auth-gap findings make this more urgent, not less.
The billing project can kick off in parallel at its viability-assessment phase, but its migration-plan phase should land after the admin API contract stabilizes.
Update — 2026-04-30: Phase 1 prototype shipped
Section titled “Update — 2026-04-30: Phase 1 prototype shipped”A visually functional UI prototype is now in place at ~/Repositories/GitHub/Adventive/adventive-admin-ui/ and deploys as a Worker (Static Assets) to genesis-admin.adventive.dev for team review. The prototype establishes the brand language, navigation IA, and operator workflows the team will validate against; it runs entirely against in-memory mocks (no backend wiring) and is not yet behind Cloudflare Access.
What it covers (15 routes):
- Dashboard — operator landing with revenue KPIs, 12-month stacked-area trend, recent invoices, managed-services queue, quick links.
- Accounts — list with status filters and search; detail page with all 9 tabs (Settings, Users, Campaigns, Ad Units, Advertisers, Billing History, Permissions & Entitlements, Plan Info, Managed Services).
- Billing — Overview (KPIs + trend/breakdown chart toggle + collections progress + aging snapshot), Invoices, Account Revenue History (12-month per-account grid), Processing controls, Delinquent, Aging Summary.
- Tools — Preview Link Lookup, User Lookup, Ad Type Utilization, Ad Type Performance, Cognito Sync, Special Permissions catalog.
Stack chosen and proven: Vite 8 + React 19 + TypeScript + Tailwind 3 + shadcn-flavored primitives + TanStack Router (code-based) + TanStack Query + Recharts. Brand tokens are HSL CSS variables lifted directly from brandguide.adventive.com/dashboard (dark theme, primary purple 250 100% 70%, radius 0.75rem, Stripe-style accent palette, Inter font).
The prototype’s mock data layer at src/lib/mock/ is deliberately structured to mirror the API contract this project will define — replacing it with TanStack Query hooks against adventive-admin-api is the primary handoff between Phase 1 and Phase 2.
Update — 2026-04-30: Phase 2 locked decisions
Section titled “Update — 2026-04-30: Phase 2 locked decisions”Three open API/architecture questions were closed during the Phase 1 hand-off conversation and are now locked:
-
API surface shape — hybrid REST + composite endpoints. Strict REST per resource (
GET /accounts,/campaigns,/invoices,/users, etc.) plus a small set of composite endpoints for heavy screens. The canonical example:GET /accounts/:id?include=users,campaigns,adunits,advertisers,invoices,managedjobs,permissions,planreturns the full Account Detail screen in one round-trip. Avoids the 9-call waterfall a strict-REST design would force on the legacy/account/detailtabbed page without over-fitting the API to the UI. -
Auth posture — Cloudflare Access JWT + Worker session for CSRF/idempotency. Cloudflare Access at the edge handles authn (JumpCloud SAML + WebAuthn replaces the legacy LDAP + Duo flow entirely; the JumpCloud
Admin Dashboardgroup becomes the Access policy). The Worker layers a lightweight signed-cookie session on top — KV-backed — that issues CSRF tokens for mutations, idempotency keys for billing actions, and seeds an audit trail. Defense-in-depth that matters specifically for the billing/processing surface. -
Billing scope — read-only in v1, mutations deferred to Stripe Billing Transition. Read-only billing endpoints (overview, invoice list, account history, aging, delinquent) ship in admin-api Phase 2 so the prototype becomes review-able end-to-end. Mutating billing endpoints (test invoice generation, QuickBooks export, dunning sweep, year-end rollover) stay mocked in the UI until the Stripe Billing Transition project provides their replacement. Documented as a deliberate handoff to that project.
These three decisions, plus the existing ADRs for Cloudflare Access, the React SPA stack, and the no-CodeIgniter-retrofit deployment strategy, fully constrain the Phase 2 implementation. The adventive-admin-api Worker scaffold at ~/Repositories/GitHub/Adventive/adventive-admin-api/ reflects them in code.
Update — 2026-04-30: Phase 2 prerequisites surfaced by deeper analysis
Section titled “Update — 2026-04-30: Phase 2 prerequisites surfaced by deeper analysis”A deep code analysis pass (Phase 2 kickoff) added findings beyond §01:
- Auth replacement is cleaner than originally assumed. Legacy uses JumpCloud LDAP bind +
Admin Dashboardgroup check + Duo Universal Prompt 2FA. Cloudflare Access fully replaces all three layers with a single JumpCloud SAML/SCIM connector and WebAuthn second-factor. The new admin-api never ships withAuth.php,Jc_authlibrary, or the Duo SDK — entire surface area removed. - Four-database topology, not one. Beyond
console(HyperdriveDB_CONSOLEalready provisioned at059838c4abb64a92a4aece2a6a533a29for dev), the legacy admin reads frombilling(invoicing/payments),aggregate_ro(KPI event metrics), anddata_warehouse(Redshift, used only by Report.php). Phase 2 dev needs onlyDB_CONSOLE. Stg/prd planning must provision additional Hyperdrives forbillingandaggregate_ro— captured in §03’s environment matrix. - 20+ snowflake customer reports do not migrate as-is.
Report.php(~5200 LOC) contains custom SQL for Sonoma, HighSnobiety, Pulpo, NPM, FarmJournal, Afar, Bridgetower, DoubleVerify, Plugshare, Atlantic, Boston Globe, SF Gate, etc. Each is a one-off CSV export with 3–5 join queries. Recommendation: move to versioned templates or a BI tool; do not port to admin-api. Deferred to a Phase 4 analytics-service evaluation. - External microservice coupling. Three internal HTTP services (
billing_service,account_service,asset_service) are called from PHP via raw curl with no timeout, retry, or circuit-breaker. Phase 2 wraps these with proper resilience (timeout + exponential backoff + bulkhead). Thebilling_serviceboundary is co-owned with the Stripe Billing Transition project. - Hardcoded production secrets in
application/config/adventive.php— full inventory now visible: AWS IAM key/secret, Mailgun API key, Duo secret key, JumpCloud bind password, Bitbucket OAuth token. All require rotation at migration cutover; remediation is a hard prerequisite, not a Phase 2 task. The new admin-api has no equivalent secrets — Cloudflare Access replaces auth credentials, Hyperdrive replaces DB credentials at the binding layer, Mailgun and S3 calls are deferred to billing/billing_service.
These prerequisites are captured downstream: §02 details the new Worker’s surface; §03 details the binding/secret topology; §05 captures the rotation and decommission plan.
Reference — Legacy adventive-admin architecture (current state)
Section titled “Reference — Legacy adventive-admin architecture (current state)”Source: Deep code analysis performed 2026-04-30 against ~/Repositories/BitBucket/adventive-admin/ (CodeIgniter, version 3.3.9). Promoted from personal Claude memory into this chapter on 2026-06-02 so the reference is team-visible. Treat the legacy repository as read-only until decommissioned.
- CodeIgniter 3.1.x on PHP 7.3.
- Composer dependencies that affect the migration:
aws/aws-sdk-php,duosecurity/duo_universal_php,chriskacerguis/codeigniter-restserver,phpoffice/phpspreadsheet(PHPExcel is still imported in legacy code paths),firebase/php-jwt,paragonie/sodium_compat. - Front end: jQuery + Bootstrap + DataTables + AmCharts + ACE editor + Select2. Versions are not pinned.
- Sessions: PHP native file handler on the filesystem — does not scale across replicas.
Authentication flow (legacy)
Section titled “Authentication flow (legacy)”JumpCloud LDAP bind → JumpCloud Admin Dashboard group check → Duo Universal Prompt 2FA → session sets logged_in=true and 2fa_authd=true. Every controller’s __construct() calls jc_auth->is_authenticated(). No CSRF tokens. No fine-grained roles — JumpCloud group membership is the only RBAC.
Migration implication: Cloudflare Access replaces the entire chain. JumpCloud becomes the SAML IdP (or SCIM); Access enforces the Admin Dashboard group; WebAuthn replaces Duo. The Auth.php controller, the Jc_auth library, and the Duo SDK are removed from the new admin-api entirely.
Databases
Section titled “Databases”Four databases are configured in application/config/database.json:
console— primary; account, campaign, and ad metadata. HyperdriveDB_CONSOLEexists at id059838c4abb64a92a4aece2a6a533a29for dev.billing— invoicing and payments. No Hyperdrive provisioned yet.aggregate_ro/aggregate_rw— event metrics read replicas (KPI tables). No Hyperdrive provisioned yet.data_warehouse— Redshift via PostgreSQL PDO; analytics for some customer reports. Out of scope for admin-api; do not access from a Worker.
Stg and prd planning must provision Hyperdrives for billing and aggregate_ro before reaching parity with legacy.
External integrations
Section titled “External integrations”- AWS Cognito — user-pool sync via
AwsCognito.phplibrary. Operations:adminUpdateUserAttributes(),getUser(). Entry points:Tools/cognitoCheckUser,Tools/cognitoSyncUser. JWTs are stored in the cookieaws-cognito-app-access-token. - AWS S3 — override-file versioning via
AmazonS3.phplibrary. CRUD operations on theoverridesbucket (domainoverrideXXX.adventivecdn.com). Entry point:Override/*controller. - AWS EC2 + SSM —
AppDeploy.phplibrary, used for the “deployment users” sidebar list and SSM parameter fetching. Likely deprecated in the cloud-native admin. - Mailgun —
Mailgun.phpcurl-based wrapper. Templates:invoice_new,invoice_notify,invoice_pastdue. Most email sends are invoked indirectly via the externalbilling_service. - Duo Security — replaced by Cloudflare Access WebAuthn in the new admin.
- JumpCloud LDAP — replaced by Cloudflare Access SAML/SCIM in the new admin.
External microservices (HTTP from PHP)
Section titled “External microservices (HTTP from PHP)”billing_service— invoices, payments, revenue history. Owned by the Stripe Billing Transition project. The new admin-api should consume read-only endpoints during transition; mutations move tobilling_serviceentirely.account_service— account creation (Account/validateNewAccountPOST).asset_service— ad-thumbnail generation (Campaign/copyAdOrTemplate*).
All three are called with raw curl, no timeout, no retry, and no circuit breaker. Phase 2 wraps these with proper resilience (timeout + exponential backoff + bulkhead).
Controller surface
Section titled “Controller surface”HTML and JSON are mixed in single controllers. The only true REST endpoints are Campaign_Controller and Managedservices_Controller (both subclass REST_Controller). Everything else returns HTML or returns JSON via json_encode.
Controllers worth porting: Account (list, detail, getUsers, updateAccountAdmin, getCountryRegions), Billing (read-only: index, invoices, history, viewDelinquentInvoices; write paths defer to billing_service), Tools (lookup, userlookup, adtypes, videoBenchmarks, specialPermissions, userSearch, cognito*), Campaign (detail, copyAdOrTemplate*), Override (S3 file CRUD), ManagedServiceJob (create/update), Dashboard, Chart (data-only endpoints).
Controllers NOT to port as-is: Report (~5200 LOC, 20+ customer-specific raw-SQL queries — Sonoma, HighSnobiety, Pulpo, NPM, FarmJournal, Afar, Bridgetower, DoubleVerify, Plugshare, Atlantic, BostonGlobe, SfGate, etc.). Move to a data warehouse plus BI tool, or to versioned templates. Deferred to a Phase 4 analytics-service evaluation.
Security findings flagged for remediation
Section titled “Security findings flagged for remediation”- Hardcoded AWS IAM keys, Mailgun API key, Duo secret key, JumpCloud bind password, and Bitbucket OAuth tokens in
application/config/adventive.php. Rotate at migration cutover. - SQL-injection risk in
Report_model(string concatenation for table and column names). - No CSRF protection on forms.
- DataTables endpoint disables the PHP memory limit (
ini_set('memory_limit', -1)). - No rate limiting on report endpoints.
- No audit logging on mutations.
Performance hotspots
Section titled “Performance hotspots”Account/detail— O(n) queries for accounts, campaigns, ads. No pagination.Billing/history— aggregates all-time invoice data; no date-range filter on the base query.Billing/getMonthSummary— 6+ nested queries in a loop; builds the XLSX in memory.Tools/videoBenchmarks— KPI-table aggregation without obvious indexing.Campaign_Controller/get— DataTables loads the full result into memory.
Repository location
Section titled “Repository location”~/Repositories/BitBucket/adventive-admin/ — read-only reference until decommissioned. Do not modify.