Skip to content

02 — Code Updates / Migration Plan

Summary of changes

Greenfield replacement. Two new repositories (adventive-admin-api and adventive-admin-ui) ship in parallel with the existing CodeIgniter admin at ~/Repositories/BitBucket/adventive-admin. Both read/write the same backing database during the transition via Cloudflare Hyperdrive (MySQL connection pooling). Operators migrate cohort-by-cohort. The CodeIgniter admin is not modified — it is decommissioned once parity is reached and a 30-day freeze window completes.

Before beginning implementation: production secrets (application/config/adventive.php) must be rotated and moved to AWS Secrets Manager or Cloudflare secrets. This is a prerequisite, not a Phase 1 task.

Target repository layout

adventive-admin-api/                 (TypeScript / Hono on Cloudflare Workers)
├── src/
│   ├── index.ts                     # Hono app entrypoint + CF Access middleware
│   ├── auth/
│   │   ├── access.ts                # CF-Access-Jwt-Assertion validation
│   │   └── rbac.ts                  # Role derivation from Access email → super-admin/billing/read-only
│   ├── routes/
│   │   ├── customers.ts             # GET/PATCH /customers, /customers/:id
│   │   ├── users.ts                 # GET /customers/:id/users, POST /users/:id/unlock
│   │   ├── accounts.ts              # Account settings, activation, cancellation
│   │   ├── campaigns.ts             # GET /campaigns, /ads (per account)
│   │   ├── invoices.ts              # GET /invoices → reads Stripe
│   │   ├── billing-profiles.ts      # GET/PUT /billing-profiles/:account_id
│   │   ├── managed-jobs.ts          # CRUD /managed-jobs
│   │   ├── overrides.ts             # CRUD /overrides (R2-backed)
│   │   ├── service-levels.ts        # Account plan/tier management
│   │   ├── charts.ts                # GET /charts/* (account reg, revenue, ads)
│   │   ├── tools.ts                 # User lookup, preview lookup, ad types
│   │   └── operators.ts             # Operator RBAC management
│   ├── db/
│   │   ├── client.ts                # Hyperdrive MySQL client
│   │   ├── queries/
│   │   │   ├── accounts.ts          # Port of Account_model queries
│   │   │   ├── campaigns.ts         # Port of Campaigns_model queries
│   │   │   ├── managed-jobs.ts      # Port of ManagedService_model queries
│   │   │   └── charts.ts            # Port of Dashboard_model + Chart queries
│   │   └── schema.ts                # Table name constants
│   ├── stripe/
│   │   └── client.ts                # Stripe SDK wrapper (invoice reads, customer reads)
│   ├── r2/
│   │   └── overrides.ts             # R2 operations for override file versioning
│   └── schemas/
│       └── *.ts                     # Zod schemas → @hono/zod-openapi
├── wrangler.toml
├── vitest.config.ts
└── test/
    ├── routes/
    └── auth/

adventive-admin-ui/                  (React + Vite on Cloudflare Pages)
├── src/
│   ├── main.tsx
│   ├── app/
│   │   ├── router.tsx               # TanStack Router config
│   │   └── query-client.ts          # TanStack Query config
│   ├── features/
│   │   ├── dashboard/               # Dashboard overview → replaces Dashboard.php view
│   │   ├── customers/               # Account list, detail, create, activate, cancel
│   │   ├── billing/                 # Invoice list, payment, profiles, delinquent
│   │   ├── managed-jobs/            # Managed service job CRUD
│   │   ├── campaigns/               # Campaign + ad list, ad copy
│   │   ├── overrides/               # Override file versioning
│   │   └── tools/                   # User lookup, ad types, benchmarks, deploy
│   ├── api/
│   │   └── generated.ts             # Types generated from admin-api OpenAPI spec
│   ├── components/
│   │   ├── ui/                      # shadcn/ui primitives
│   │   └── brand/                   # Adventive brand overrides (colors, typography)
│   └── lib/
│       └── access.ts                # Read CF Access identity from /me endpoint
├── public/
│   └── _redirects                   # SPA fallback for CF Pages deep links
├── vite.config.ts
└── e2e/                             # Playwright
    └── flows/
        ├── account-management.spec.ts
        └── billing.spec.ts

Before / after

Before

  • Monolithic CodeIgniter 3.1 app: PHP controllers render HTML views, same process handles DB access, billing rollup, invoice rendering, file I/O, and scheduled report delivery.
  • Auth: JumpCloud LDAP → Duo 2FA → CI session. Currently: LDAP only (Duo disabled).
  • Secrets: hardcoded in application/config/adventive.php.
  • CSRF: globally disabled.
  • Deploy: Bitbucket Pipelines → AWS CLI → CodeDeploy → EC2. Shared deploy-script repo (shell).
  • Observability: EC2 server logs; no structured metrics or alerts.

After

  • Three services: admin-api Worker (API), admin-ui Pages (presentation), invoice-renderer Worker (billing — Stripe Billing Transition scope).
  • Auth: Cloudflare Access at the edge (JumpCloud or Google Workspace, deferred). Admin-api validates CF-Access-Jwt-Assertion on every request. No application-managed sessions.
  • Secrets: Wrangler secret / Cloudflare environment variables. Nothing committed to source.
  • CSRF: eliminated — stateless JWT architecture has no session to forge.
  • Deploy: GitHub Actions → wrangler deploy (Worker) + Pages CI/CD (SPA). Single command per environment.
  • Observability: Workers Analytics Engine + Logpush → existing log sink.

Migration phases

Phase Scope Gate to next
0 Pre-work: Rotate and remove hardcoded secrets from adventive.php. Move to AWS Secrets Manager. This is a prerequisite. Secrets cleared from source history
1 Scaffold admin-api Worker (Hono skeleton, CF Access middleware, RBAC, stub endpoints) + admin-ui Pages (Vite + shadcn/ui + TanStack Router skeleton). Deploy to preview URLs. Cloudflare Access policy provisioned for all ~10 operators. Preview deploys green; all operators can authenticate
2 Implement customer + account management domain (Cohort 1 workflows 1–12): account list, detail, create, activate, cancel, user lookup, unlock, settings. RBAC enforcement. Full test coverage. Feature parity checklist for cohort 1 complete
3 Cohort 1 migration — account-management operators move to new admin. Legacy stays live. Collect feedback, iterate UI. Cohort retention at new admin ≥ 2 weeks with no rollback
4 Implement billing read surface (Cohort 2 workflows 13–25): invoice list/detail from Stripe, billing profiles, delinquent view, revenue history, managed services. Co-develops with Stripe Billing Transition Phase B. Billing parity checklist complete; Stripe SoR stable
5 Cohort 2 migration — billing-ops operators move to new admin. Cohort retention ≥ 2 weeks
6 Implement campaigns, managed service jobs, override files (Cohort 3 workflows 26–31). Parity checklist complete
7 Cohort 3 migration — remaining operators. All operators on new admin
8 Phase 4 deferred items: tooling (deploy, Cognito sync, benchmarks), partner report evaluation. All workflows covered or explicitly deferred
9 Freeze legacy admin (read-only mode). Start 30-day freeze window. 30 days clean
10 Decommission CodeIgniter admin. Archive repo.

File-by-file change list

Legacy files are not modified — they are inventoried so the replacement is feature-complete.

Legacy file Lines Replaced by Risk Notes
application/controllers/Auth.php 205 Cloudflare Access (no code equivalent) Low Auth moved entirely to edge; no application auth controller
application/controllers/Dashboard.php 42 admin-api/src/routes/charts.ts + UI dashboard feature Low Simple aggregation
application/controllers/Account.php 460 admin-api/src/routes/customers.ts, accounts.ts, users.ts Medium CRUD + account-service API call replicated in Worker
application/controllers/Billing.php 960 admin-api/src/routes/invoices.ts, billing-profiles.ts (Stripe reads) High Invoice generation retired; payment processing via Stripe; PDF stays in invoice-renderer Worker
application/controllers/Campaign.php 111 admin-api/src/routes/campaigns.ts Medium Ad copy curl call → internal Worker call
application/controllers/Report.php 445 Phase 4 evaluation — analytics Worker or Stripe reports High 22 methods; do not port to admin-api
application/controllers/Reporting.php 997 Cloudflare Cron Trigger Workers (separate from admin-api) High 25 scheduled-delivery methods → individual Cron Triggers
application/controllers/Tools.php 451 admin-api/src/routes/tools.ts (partial) Medium App deployment tooling may be retired; Cognito sync stays
application/controllers/Override.php 167 admin-api/src/routes/overrides.ts + R2 Low S3 → R2 migration; same versioning model
application/controllers/Chart.php 98 admin-api/src/routes/charts.ts Low 4 JSON endpoints; straightforward port
application/controllers/ManagedServiceJob.php 104 admin-api/src/routes/managed-jobs.ts Low CRUD; clean port
application/controllers/Utility.php 58 Cloudflare Cron Trigger Workers or retired Low CLI-only; resetApiRequestCounts, updateLiveCampaigns
application/controllers/api/Campaign_Controller.php 117 admin-api/src/routes/campaigns.ts Low DataTables pagination → standard pagination
application/controllers/api/Managedservices_Controller.php 99 admin-api/src/routes/managed-jobs.ts Low Same
application/models/Account_model.php 1,321 admin-api/src/db/queries/accounts.ts High All queries must be reproduced with full parity
application/models/Billing_model.php 933 admin-api/src/stripe/client.ts + residual DB queries High Billing queries largely retire; Stripe reads replace most
application/models/Campaigns_model.php 665 admin-api/src/db/queries/campaigns.ts Medium
application/models/Report_model.php 5,333 Phase 4 — analytics Worker Critical Do not attempt to port inline; 24 bespoke SQL functions
application/models/ManagedService_model.php 505 admin-api/src/db/queries/managed-jobs.ts Medium
application/models/Stats_model.php 1,286 Partially retire (billing stats → Stripe); remainder in analytics Worker High
application/models/Override_model.php 280 admin-api/src/r2/overrides.ts Low S3 ops → R2 ops
application/models/Dashboard_model.php 121 admin-api/src/db/queries/charts.ts Low
application/config/adventive.php Cloudflare secrets + environment variables Critical Secrets must be rotated before this file is removed from history
application/libraries/Jc_auth.php Cloudflare Access (no application code) Low Retired entirely
application/libraries/Mailgun.php Retained in invoice-renderer Worker Low Not part of admin-api scope
application/libraries/AmazonS3.php Cloudflare R2 SDK in overrides Worker Low S3 → R2
application/libraries/AwsCognito.php Cognito SDK in tools route Low Thin wrapper retained
application/libraries/AppDeploy.php Evaluate retirement vs. thin port Low CodeDeploy tooling; may be superseded by wrangler/Actions

New files (indicative)

File Purpose
admin-api/src/index.ts Hono app entrypoint; CF Access middleware; global error handler
admin-api/src/auth/access.ts Validates CF-Access-Jwt-Assertion; extracts operator email
admin-api/src/auth/rbac.ts Maps operator email → RBAC role from config; enforces per-route
admin-api/src/db/client.ts Hyperdrive MySQL client factory
admin-api/openapi.json Generated from @hono/zod-openapi; consumed by UI type generation
admin-ui/src/api/generated.ts TypeScript types generated from OpenAPI spec
admin-ui/public/_redirects CF Pages SPA fallback: /* /index.html 200
.github/workflows/deploy-api.yml wrangler deploy on merge to main
.github/workflows/deploy-ui.yml Pages CI/CD on merge to main
admin-api/wrangler.toml Worker config: name, routes, Hyperdrive binding, R2 binding, secrets

Removed files (end of Phase 10)

  • Entire ~/Repositories/BitBucket/adventive-admin repository — archived, not deleted.

Dependencies

Added:

Package Purpose
hono HTTP framework for Workers
@hono/zod-openapi OpenAPI spec generation — single source of truth for types
zod Schema validation
stripe Stripe SDK (Workers-compatible)
react, react-dom UI framework
@tanstack/react-query Server state management
@tanstack/react-router Type-safe routing
vite Build tool
tailwindcss Utility CSS
shadcn/ui components + @radix-ui/* UI component primitives
vitest Unit testing
@playwright/test E2E testing

Removed (end of Phase 10): PHP 7.3 runtime, CodeIgniter 3.1, all composer dependencies.

Breaking changes

  • Admin URL changes during transition (operators informed by cohort).
  • Operator auth moves from JumpCloud LDAP → Cloudflare Access. All ~10 operators must be provisioned in the Access policy before Cohort 1 migrates.
  • API consumers (any automation scripts pointing at legacy admin URLs) must update to new contract.
  • billing_service internal API is retired as Stripe Billing Transition completes — any external callers must be identified.

Schema-freeze policy during transition

While both admins share the same database, no schema changes that break backward compatibility with the CodeIgniter admin may be deployed. New columns (nullable, with defaults) are acceptable. Column drops, renames, and type changes are blocked until the CodeIgniter admin is decommissioned. This policy is in effect from Phase 1 until Phase 10.

Testing strategy

Layer Tool Scope
Unit — admin-api Vitest Route handlers, Zod schemas, RBAC logic, DB query builders
Unit — admin-ui Vitest + Testing Library Components, hooks, form validation
Contract Generated OpenAPI types UI type generation catches API drift at build time
Integration admin-api against staging DB + Stripe test mode Full request/response parity with legacy behavior
E2E Playwright against Pages preview deploy CF Access service token for automation; golden-path flows per cohort
Parity Per-cohort checklist Dogfooded alongside legacy admin before cohort migration
Rollback Any cohort can return to legacy URL No data migration risk — shared DB