01 — Architecture Assessment¶
Status: complete — populated from adventive-admin repo analysis, April 2026.
Current state¶
| Attribute | Value |
|---|---|
| Application version | 3.3.9 (composer.json) |
| Language | PHP ≥ 7.3 |
| Framework | CodeIgniter 3.1.* (last release 3.1.13, 2022; no active maintenance) |
| Deploy target | EC2 (Linux) — direct server push via AWS CodeDeploy |
| CI/CD | Bitbucket Pipelines — three branch-triggered pipelines (development, staging, production) |
| Environments | development, staging, production (called "ops" in pipeline) |
| Authentication | JumpCloud LDAP (application/libraries/Jc_auth.php) + Duo 2FA (duosecurity/duo_universal_php) — Duo currently disabled (see pain points) |
| Data stores | MySQL: console DB (accounts, campaigns, plans), billing DB (invoices, profiles), aggregate DB (stats); AWS Redshift (impression events) |
| File storage | AWS S3 — invoice PDFs (billing-*.adventivecdn.com), override files (override-*.adventivecdn.com) |
Mailgun (application/libraries/Mailgun.php) |
|
| Integration endpoints | Internal billing_service API, AWS Cognito, AWS CodeDeploy, Bitbucket OAuth, DoubleVerify |
Traffic profile: Internal only. Low volume, concentrated around month-end billing operations. Peak: ~10 concurrent operators.
Code inventory¶
Top-level folder tree¶
adventive-admin/
├── application/
│ ├── config/ (21 files — routes, database, adventive.php, mailgun.php, rest.php)
│ ├── controllers/ (12 controllers + 2 API sub-controllers)
│ ├── models/ (13 models, 11,172 total lines)
│ ├── libraries/ (9 libraries: Jc_auth, Mailgun, AmazonS3, AwsCognito,
│ │ AwsAthena, AppDeploy, REST_Controller, Duo wrapper)
│ ├── views/ (56 view files across 11 directories)
│ ├── helpers/ (csv, download, file helpers)
│ ├── hooks/
│ ├── data/
│ └── cache/
├── www/ (public web root, index.php)
├── tests/ (test directory — no test files found)
├── logs/
├── composer.json (version 3.3.9, PHP ≥ 7.3)
├── appspec.yml (AWS CodeDeploy — currently inactive, replaced by shell repo)
└── bitbucket-pipelines.yml
Route map (controllers → URL patterns)¶
| Controller | URL prefix | Method count | Lines |
|---|---|---|---|
Dashboard.php |
/dashboard |
1 | 42 |
Auth.php |
/auth |
4 | 205 |
Account.php |
/account |
10 | 460 |
Billing.php |
/billing |
18 | 960 |
Campaign.php |
/campaign |
3 | 111 |
Report.php |
/report |
22 | 445 |
Reporting.php |
/reporting |
25 | 997 |
Tools.php |
/tools |
14 | 451 |
Override.php |
/override |
8 | 167 |
Chart.php |
/chart |
4 | 98 |
ManagedServiceJob.php |
/managedservicejob |
2 | 104 |
Utility.php |
/utility (CLI only) |
2 | 58 |
api/Campaign_Controller.php |
/api/campaign |
2 | 117 |
api/Managedservices_Controller.php |
/api/managedservices |
2 | 99 |
Route config (application/config/routes.php) has minimal explicit routes — most routing is CodeIgniter's default controller/method/param convention.
Models → database tables¶
| Model | File | Lines | Tables | Primary operations |
|---|---|---|---|---|
Account_model |
Account_model.php |
1,321 | account, users, account_executive |
SELECT, UPDATE, INSERT |
Billing_model |
Billing_model.php |
933 | billing_invoice, billing_invoice_account, billing_invoice_usage, billing_profiles, account_plan, account_plan_sub, account_plan_usage |
SELECT, INSERT, UPDATE |
Campaigns_model |
Campaigns_model.php |
665 | campaign, client, ad_html5, ad_format |
SELECT, INSERT |
Report_model |
Report_model.php |
5,333 | campaign, ad_html5, stats_aggregate_*, impressions (Redshift) |
SELECT (complex analytical) |
ManagedService_model |
ManagedService_model.php |
505 | managed_service_jobs, managed_service_jobs_ads, managed_service_impression_log, managed_service_job_log |
SELECT, INSERT, UPDATE |
Stats_model |
Stats_model.php |
1,286 | stats_* aggregate tables |
SELECT, INSERT |
Override_model |
Override_model.php |
280 | override_file_descriptions + S3 |
S3 + DB |
Dashboard_model |
Dashboard_model.php |
121 | account |
SELECT |
Advertiser_model |
Advertiser_model.php |
112 | client |
SELECT, INSERT |
Tools_model |
Tools_model.php |
298 | various | SELECT |
Utility_model |
Utility_model.php |
89 | account, api_keys |
UPDATE |
Pdo_model |
Pdo_model.php |
124 | (generic PDO wrapper for Redshift) | Generic |
Uuid_model |
Uuid_model.php |
105 | — | UUID generation utility |
Views → operator workflow identification¶
| Directory | File count | Operator surface |
|---|---|---|
views/account/ |
12 | Account list, detail, creation wizard, activation, cancellation |
views/billing/ |
11 | Billing dashboard, invoice list, processing forms, delinquent, managed services |
views/campaign/ |
1 | Campaign + ad list |
views/dashboard/ |
1 | Main dashboard |
views/report/ |
5 | Report listing, queue status |
views/tools/ |
14 | Lookup tools, ad types, benchmarks, permissions, deployment |
views/override/ |
2 | Override file editor + version viewer |
views/auth/ |
2 | Login form, Duo 2FA prompt |
views/common/ |
7 | Header, footer, sidebar, JS includes |
views/errors/ |
10 | Error pages |
Third-party libraries (composer.json)¶
| Package | Version | Status | Notes |
|---|---|---|---|
codeigniter/framework |
3.1.* |
⚠️ End-of-life | No active maintenance since 2022 |
aws/aws-sdk-php |
3.324.* |
✓ Active | S3, Cognito, Athena |
chriskacerguis/codeigniter-restserver |
^3.1 |
⚠️ Community | Not officially maintained; REST framework for CI3 |
phpoffice/phpexcel |
1.7.9 |
🚨 Abandoned | Archived 2019; no security patches. Used by Billing::getMonthSummary |
phpoffice/phpspreadsheet |
1.25.* |
✓ Active | Successor to PHPExcel — both installed simultaneously |
mk-j/php_xlsxwriter |
^0.39 |
✓ Active | Third Excel library; three overlapping Excel dependencies |
duosecurity/duo_universal_php |
^1.0 |
✓ Active | Currently disabled in application |
paragonie/sodium_compat |
^1.21 |
✓ Active | Libsodium polyfill |
firebase/php-jwt |
^6.4 |
✓ Active | JWT support |
phan/phan |
^1 (dev) |
⚠️ Outdated | Static analysis tool; current major is v5 |
Scheduled tasks / cron jobs¶
Reporting.php (997 lines) is the cron-facing controller. Its 25 public methods are called by server cron jobs via HTTP — no auth check in the constructor (the class extends CI_Controller without the jc_auth->is_authenticated() guard present in all other controllers). Each method fetches data from Report_model, generates a CSV/Excel file, and emails it to a partner contact via Mailgun.
Partner reports delivered on schedule:
| Method | Schedule (implied) | Recipient |
|---|---|---|
runRefineryDaily |
Daily | Refinery Media |
runSfGateXMLWeekly |
Weekly | SF Gate |
runBridgetowerMonthly |
Monthly | BridgeTower Media |
runHerCampusDaily |
Daily | Her Campus |
runHerCampusMonthlySite |
Monthly | Her Campus (per site) |
runRefineryMonthlySite |
Monthly | Refinery (per site) |
runSagaCityQuarterlySite |
Quarterly | Saga City |
runGoYuitMonthly |
Monthly | GoYuit |
runMansuetoDoubleVerifydaily |
Daily | Mansueto / DoubleVerify |
runMoveDoubleVerifydaily |
Daily | Move / DoubleVerify |
runFarmJournalMonthly |
Monthly | Farm Journal |
runMorganMurphyMonthly |
Monthly | Morgan Murphy Media |
runSonomaWeekly |
Weekly | Sonoma Media |
runHighSnobietyMonthly |
Monthly | HighSnobiety |
runAfarMonthly |
Monthly | Afar |
runNPRMonthly |
Monthly | NPR |
runAtlanticMonthly |
Monthly | The Atlantic |
runPulpoMonthly |
Monthly | Pulpo |
runPulpoWeekly |
Weekly | Pulpo |
runPulpoDaily |
Daily | Pulpo |
runPulpoPreviousDay |
Daily | Pulpo |
Utility.php (CLI only) provides resetApiRequestCounts and updateLiveCampaigns — system maintenance tasks run from CLI, not HTTP.
Integration endpoints¶
| Integration | Usage | Library / mechanism |
|---|---|---|
Internal billing_service API |
Invoice generation, payment processing, ACH info, remittance | file_get_contents() + curl POST (Billing_model.php) |
| AWS S3 | Invoice PDFs, override files, report exports | application/libraries/AmazonS3.php (aws-sdk-php) |
| AWS Cognito | User sync, OAuth | application/libraries/AwsCognito.php |
| AWS Redshift | Impression analytics queries | application/models/Pdo_model.php (PDO direct) |
| AWS Athena | Events querying | application/libraries/AwsAthena.php |
| Mailgun | Invoice emails, report delivery | application/libraries/Mailgun.php |
| JumpCloud LDAP | Operator authentication | application/libraries/Jc_auth.php |
| Duo Security | 2FA (currently disabled) | duosecurity/duo_universal_php |
| DoubleVerify | Ad verification report data | Direct HTTP calls in Report_model.php |
| Bitbucket OAuth | App deployment | Tools.php + curl |
| AWS CodeDeploy | Application deployments | application/libraries/AppDeploy.php |
Domain decomposition¶
| Domain | Current surface | Planned API seam | Stripe Billing Transition impact | Notes |
|---|---|---|---|---|
| Account / customer management | Account.php, Account_model.php, Dashboard.php |
admin-api /customers, /dashboard |
None — accounts stay in legacy DB | Core operator workflow; cohort 1 |
| Service-level management | Account.php (settings), ManagedServiceJob.php, Override.php |
admin-api /service-levels, /managed-jobs, /overrides |
None | Cohort 2 |
| Campaigns & ads | Campaign.php, api/Campaign_Controller.php, Campaigns_model.php |
admin-api /campaigns, /ads |
None | Cohort 3; ad copy is super-admin only |
| Billing — invoice view | Billing.php (view methods), Billing_model.php |
admin-api /invoices → reads Stripe |
Billing transitions to Stripe as SoR | Admin becomes a Stripe-read view |
| Billing — payment processing | Billing::processPayment |
Replaced by Stripe Checkout / PaymentIntent | Stripe owns payment collection | Manual payment entry via Stripe Dashboard |
| Billing — invoice PDF + email | billing_service API → S3 → Mailgun |
invoice-renderer Worker → R2 → Mailgun |
Custom PDF retained (ADR) | Webhook-driven off invoice.finalized |
| Billing — month-end rollup | Billing::getMonthSummary, generateInvoices |
Retired — Stripe accumulates InvoiceItems as-they-happen | Rollup job fully retired | Excel summary report may be reimplemented as a Stripe-read report |
| Operator auth / sessions | Auth.php, Jc_auth.php, CI sessions |
Cloudflare Access (edge-terminated) | None | Directory choice deferred |
| Partner reports (scheduled) | Reporting.php, Report_model.php |
Cloudflare Cron Trigger Workers | None | 25 methods → Cron Triggers; deferred to Phase 4 |
| Partner reports (on-demand) | Report.php, Report_model.php |
Deferred — dedicated analytics service evaluation | None | 5,333-line god-model; not in admin-api scope |
| Tooling (deploy, Cognito) | Tools.php |
admin-api /tools |
None | App deployment UI; Cognito sync stays |
| Chart / metrics data | Chart.php |
admin-api /charts |
None | Simple aggregates off existing DB |
Strengths¶
- Auth is already isolated:
Jc_auth.phpandDuolibraries are clean seams — dropping them for Cloudflare Access requires only removing thejc_auth->is_authenticated()guard in each controller constructor. No auth logic is scattered through controllers. - Models are well-separated from controllers: The PHP model/controller split means DB queries can be read and ported without reverse-engineering view logic.
- Billing DB is already separate:
billingdatabase is physically separate fromconsole— Stripe Billing Transition can take over the billing DB tables without schema conflict. - Deployment is environment-parameterized: Bitbucket Pipelines to CodeDeploy pattern is understood; Cloudflare Workers + Pages CI/CD mirrors the same branch→environment model.
- Mailgun is already library-isolated:
application/libraries/Mailgun.phpis a clean seam — invoice-renderer Worker can call the same Mailgun API without touching the admin-api codebase. - No test debt to preserve: the
tests/directory is empty — no legacy test suite to port.
Pain points¶
P1 — 🚨 CRITICAL: Production secrets hardcoded in source
application/config/adventive.php contains AWS access keys, S3 secrets, and Bitbucket OAuth credentials for all three environments in plaintext. Production key AKIAIAPRP6JG4QQK3YZA is visible in the source history. The file comment reads "to be removed upon inclusion of reading from aws-secretsmanager" — never completed. Remediation is required before migration begins.
P2 — ⚠️ CSRF protection globally disabled
application/config/config.php:320 — 'csrf_protection' => false. Mutations (account creation, billing operations, settings changes) have no per-request token protection. The admin relies entirely on session auth. Cloudflare Access + the new API's JWT validation replaces this at the architectural level, but the gap is live today.
P3 — ⚠️ Duo 2FA currently bypassed
Most recent auth commit: config(auth): temporarily disable the DUO. Current operator auth is JumpCloud username/password only — no second factor. Live until Cloudflare Access is in place.
P4 — ⚠️ MD5-based payment link security
Billing.php:561 — $payNowUrl .= md5($invoice->payment_customer_id . $invoice->inv_uuid . $invoice->acct_id). MD5 is cryptographically broken for integrity purposes. If payment_customer_id is known or guessable, the link can be forged. Replaced by Stripe Checkout Sessions in the target architecture.
P5 — 📦 phpoffice/phpexcel 1.7.9 — abandoned library
Archived 2019. No security patches. Billing::getMonthSummary depends on it directly. Both PHPExcel and its successor phpspreadsheet are installed simultaneously — three Excel libraries total with mk-j/php_xlsxwriter. The month-end summary generator must migrate to phpspreadsheet (or be retired when Stripe owns the billing data).
P6 — 📊 Report_model.php at 5,333 lines — god-model
24 functions, each 100–300 lines of partner-specific SQL with hardcoded account IDs, campaign IDs, and date arithmetic. Analytical queries span Redshift and the MySQL console DB. This is not portable to a standard Hono CRUD route — it requires a dedicated analytics service decision. Recommend Phase 4 deferral with explicit evaluation.
P7 — 🔒 Reporting.php cron controller is unauthenticated HTTP
The Reporting controller has no jc_auth->is_authenticated() guard. Any HTTP client that knows the route can trigger a report delivery. In the serverless architecture these become Cloudflare Cron Triggers — auth is handled by the Workers runtime, not application code.
P8 — 🗄️ Raw SQL strings in models
Billing_model.php constructs SQL as interpolated strings in multiple places (e.g., lines 33, 86, 101, 148, 193, 256, 329, 347, 432). While values are mostly bound via CodeIgniter's query-builder binds, the pattern mixes interpolated and bound queries, making injection audits difficult. All queries rewritten as parameterized Hono/Drizzle queries in the target.
P9 — 📦 Deploy process requires SSH + AWS CLI in CI runner
bitbucket-pipelines.yml bootstraps aws-cli and openssh in an Alpine container on each deploy, clones the private shell repo for deploy scripts, then calls proprietary updateApp.sh. This is fragile and environment-specific. Target: wrangler deploy from GitHub Actions — a one-command deploy with no shared-state scripts.
P10 — 📝 No test coverage
tests/ directory is empty. Zero test coverage. phan/phan (static analysis) is in require-dev at version 1 (current: 5) and shows no evidence of active use. Target architecture has unit tests (Vitest), contract tests (generated OpenAPI types), and Playwright E2E.
Target architecture (decided)¶
┌──────────────────────────────────────────────────────────────┐
│ Operators (~10) behind Cloudflare Access │
│ (directory: JumpCloud or Google Workspace, deferred) │
└───────────────┬──────────────────────────────────────────────┘
│ HTTPS + CF-Access-Jwt-Assertion
▼
┌──────────────────────────────────────────────────────────────┐
│ admin.adventive.<tld> — Cloudflare Pages (React SPA) │
│ - shadcn/ui + Tailwind, brand-guide-aligned │
│ - TanStack Router + TanStack Query │
│ - Calls admin-api exclusively │
│ - Edge-cached static bundle; deep-link via _redirects │
└───────────────┬──────────────────────────────────────────────┘
│ HTTPS, OpenAPI contract
│ JWT validated per request
▼
┌──────────────────────────────────────────────────────────────┐
│ admin-api Worker (TypeScript / Hono) │
│ - /customers /accounts /invoices /service-levels /jobs ... │
│ - RBAC: super-admin, billing, read-only │
│ - Reads Stripe for billing; legacy MySQL for everything else│
│ - MySQL via Cloudflare Hyperdrive (connection pooling) │
└───────────────┬──────────────────────────────────────────────┘
│
┌───────┼──────────────┬──────────────┐
▼ ▼ ▼ ▼
[Legacy DB [Stripe API] [Mailgun] [Public API
via (invoices Worker]
Hyperdrive] via
invoice-
renderer]
Parallel-run topology during transition:
Cloudflare Access (shared auth edge)
│ │
▼ ▼
admin.legacy.* admin.adventive.*
(CodeIgniter) (Pages SPA, new)
│ │
▼ ▼
CodeIgniter DAL admin-api Worker
│ │
└──────────┬───────────┘
▼
Shared billing / customer DB
Both admins read/write the same database during the transition. Operators migrate cohort-by-cohort; rollback is trivial (return to legacy URL).
Serverless viability assessment¶
| Dimension | Current state | Serverless fit | Notes |
|---|---|---|---|
| Statefulness | PHP sessions, CI session library | ✅ Excellent | Cloudflare Access JWT replaces sessions entirely; admin-api is stateless |
| Cold-start tolerance | Persistent PHP process (EC2) | ✅ Good | Internal tool — ~10 operators; occasional cold starts are acceptable; Hono is sub-10ms startup |
| Request duration | Typical < 500ms; month-end Excel generation can run 5–30s | ⚠️ Caution | Excel/CSV generation moves to async (Queues) or client-side; Stripe-read views are fast |
| Memory footprint | PHP process ~64–128 MB typical | ✅ Good | Hono Worker runs at ~10–20 MB; no full PHP runtime overhead |
| Dependency surface | 10 composer packages; PHPExcel abandoned | ✅ Better | npm ecosystem; no abandoned-library risk; Stripe SDK, Hono, Zod |
| PDF rendering | External billing_service generates PDF to S3 |
⚠️ Constrained | Cloudflare Browser Rendering (leading candidate) or external service for invoice-renderer Worker; out of admin-api scope |
| Secrets / config | Hardcoded in adventive.php 🚨 |
✅ Much better | Wrangler secret / Cloudflare environment variables; no committed secrets |
| Observability | Server logs on EC2; no structured metrics | ✅ Better | Workers Analytics Engine + Logpush → existing log sink |
| Cost at current scale | EC2 instance + RDS (always-on) | ✅ Lower | Workers: pay-per-request; Pages: free tier; Hyperdrive: ~$0.001/query at this scale |
| Scheduled jobs | Server cron → unauthenticated HTTP endpoints | ✅ Better | Cloudflare Cron Triggers — authenticated, managed, observable |
Recommendation: Proceed. Cloudflare Workers + Pages is a strong fit for this workload. The only constrained dimension is the billing PDF renderer — this is deliberately out of admin-api scope (handled by the invoice-renderer Worker in the Stripe Billing Transition project). All operator-facing request durations fit comfortably within the 30-second Worker limit with substantial headroom.
Operator workflow catalog¶
34 distinct operator-facing workflows, organized by cohort migration order:
| # | Workflow | Controller::method | URL pattern | RBAC tier | Frequency | Cohort |
|---|---|---|---|---|---|---|
| 1 | Login / 2FA | Auth::login |
/auth/login |
All | Daily | Pre-1 |
| 2 | Dashboard overview | Dashboard::index |
/dashboard |
All | Daily | 1 |
| 3 | List/search accounts | Account::index |
/account |
All | Daily | 1 |
| 4 | View account detail | Account::detail |
/account/:id |
All | Daily | 1 |
| 5 | Create account | Account::newAccount + validateNewAccount |
/account/newAccount |
Super-admin | Weekly | 1 |
| 6 | Activate trial account | Account::activateAccount |
/account/activateAccount |
Super-admin | Weekly | 1 |
| 7 | Cancel account | Account::cancelAccount |
/account/cancelAccount/:id |
Super-admin | Rare | 1 |
| 8 | Unlock user | Account::unlockUser |
/account/unlockUser/:id |
Super-admin | Weekly | 1 |
| 9 | Toggle account settings | Account::changeSetting |
/account/changeSetting |
Super-admin | Weekly | 1 |
| 10 | Change account admin | Account::updateAccountAdmin |
/account/updateAccountAdmin |
Super-admin | Rare | 1 |
| 11 | User lookup by email | Tools::userlookup |
/tools/userlookup |
All | Daily | 1 |
| 12 | Preview link lookup | Tools::lookup + previewSearch |
/tools/lookup |
All | Weekly | 1 |
| 13 | Billing dashboard | Billing::index |
/billing |
Billing | Daily | 2 |
| 14 | Invoice list / filter | Billing::invoices |
/billing/invoices |
Billing | Daily | 2 |
| 15 | Generate invoices (batch) | Billing::generateInvoices |
/billing/generateInvoices |
Billing | Monthly | 2 |
| 16 | Email invoice batch | Billing::emailInvoice |
/billing/emailInvoice |
Billing | Monthly | 2 |
| 17 | Send invoice reminder | Billing::sendInvoiceReminder |
/billing/sendInvoiceReminder |
Billing | Monthly | 2 |
| 18 | Process payment | Billing::processPayment |
/billing/processPayment |
Billing | Weekly | 2 |
| 19 | Update billing profile | Billing::updateBillingProfile |
/billing/updateBillingProfile |
Billing | Rare | 2 |
| 20 | View delinquent invoices | Billing::viewDelinquentInvoices |
/billing/viewDelinquentInvoices |
Billing | Monthly | 2 |
| 21 | Revenue history | Billing::history |
/billing/history |
Billing | Monthly | 2 |
| 22 | QuickBooks CSV export | Billing::generateQuickbooksCSV |
/billing/generateQuickbooksCSV |
Billing | Monthly | 2 |
| 23 | Commission report | Billing::generateCommissionReport |
/billing/generateCommissionReport |
Billing | Monthly | 2 |
| 24 | Month-end summary (Excel) | Billing::getMonthSummary |
/billing/getMonthSummary |
Billing | Monthly | 2 |
| 25 | Managed services billing overview | Billing::managedServices |
/billing/managedServices |
Billing | Monthly | 2 |
| 26 | Campaign list (account) | api/Campaign_Controller::get |
/api/campaign?resource=accountCampaigns |
All | Weekly | 3 |
| 27 | Ad list (account) | api/Campaign_Controller::get |
/api/campaign?resource=accountAds |
All | Weekly | 3 |
| 28 | Copy ad/template | Campaign::copyAdOrTemplate |
/campaign/copyAdOrTemplate |
Super-admin | Rare | 3 |
| 29 | Managed service jobs list | api/Managedservices_Controller::get |
/api/managedservices?resource=jobs |
Billing | Weekly | 3 |
| 30 | Create/edit managed service job | ManagedServiceJob::create/updateManagedServiceJob |
/managedservicejob/* |
Billing | Weekly | 3 |
| 31 | Override file versioning | Override::* |
/override/* |
Super-admin | Rare | 3 |
| 32 | Ad types / video benchmarks | Tools::adtypes, videoBenchmarks |
/tools/adtypes |
All | Rare | 4 |
| 33 | Special permissions management | Tools::specialPermissions |
/tools/specialPermissions |
Super-admin | Rare | 4 |
| 34 | Application deployment | Tools::appDeploy, deploy |
/tools/appDeploy |
Super-admin | Weekly | 4 |
Out of scope for admin-api (deferred / separate):
- Partner report downloads (22 methods in Report.php) — Phase 4 evaluation: dedicated analytics Worker or self-serve Stripe reporting
- Partner report scheduled deliveries (25 methods in Reporting.php) — Cloudflare Cron Trigger Workers, separate from admin-api
Data model — billing tables fate¶
| Table | Database | Fate | Owned by |
|---|---|---|---|
billing_invoice |
billing | Retire — Stripe Invoice becomes SoR | Stripe Billing Transition |
billing_invoice_account |
billing | Retire — Stripe InvoiceItem | Stripe Billing Transition |
billing_invoice_usage |
billing | Retire — Stripe usage records | Stripe Billing Transition |
billing_profiles |
billing | Partial retire — address/ACH fields move to Stripe Customer; stripe_customer_id column stays |
Stripe Billing Transition |
account_plan |
console | Retain during transition; long-term map to Stripe Products/Prices | Admin project (read-only in new admin) |
account_plan_sub |
console | Retain during transition; migrates to Stripe Subscription | Stripe Billing Transition |
account_plan_usage |
console | Retain during transition; migrates to Stripe Prices (graduated) | Stripe Billing Transition |
account |
console | Retain — customer record mirrors Stripe Customer via stripe_customer_id |
Admin project |
users |
console | Retain | Admin project |
campaign, client, ad_html5 |
console | Retain | Admin project |
managed_service_jobs |
console | Retain | Admin project |
override_file_descriptions |
console | Retain — file references migrate from S3 to R2 | Admin project |
Decisions logged¶
- 2026-04-23 — Operator auth: Cloudflare Access. Directory integration (JumpCloud vs. Google Workspace) deferred. See
decisions/2026-04-23-cloudflare-access-for-operator-auth.md. - 2026-04-23 — UI stack: React + Vite + TypeScript SPA on Cloudflare Pages. shadcn/ui + Radix + Tailwind + TanStack Query + TanStack Router. See
decisions/2026-04-23-ui-stack-react-spa.md. - 2026-04-23 — Deployment strategy: parallel run, cohort migration, no CodeIgniter retrofit. See
decisions/2026-04-23-ship-together-no-codeigniter-retrofit.md. - 2026-04-23 — Data store: existing DB stays, admin-api connects directly via Hyperdrive during transition. No data migration in this project scope.
- 2026-04-23 — Invoice PDF renderer retained (Stripe Billing Transition ADR). Custom Handlebars renderer moves to a dedicated
invoice-rendererWorker. See sibling projectdecisions/2026-04-23-custom-invoice-pdf-retained.md. - 2026-04-23 — Stripe owns billing source of truth (Stripe Billing Transition ADR). Month-end rollup retired. Admin billing surface becomes a Stripe-read view. See sibling project
decisions/2026-04-23-stripe-billing-scope.md.
Open architectural questions¶
- Partner report surface — 5,333-line
Report_model.phpwith 24 hardcoded partner SQL queries. Options: (a) port to dedicated analytics Worker, (b) retire as partners migrate to Stripe self-serve, (c) thin wrapper exposing Redshift queries via admin-api. Needs evaluation in Phase 4. - R2 vs. S3 for override files — Current override files live in S3 (
override-*.adventivecdn.com). Natural migration target is Cloudflare R2 (no egress fees, Workers-native). Decision needed before Phase 3 implementation. - Cohort migration order (confirmed) — Workflows 1–12 (accounts/lookup) → Workflows 13–25 (billing, coordinated with Stripe transition) → Workflows 26–31 (campaigns, managed services, overrides) → Workflows 32–34 + partner reports.
- App deployment tooling —
Tools::appDeploycurrently orchestrates CodeDeploy via Bitbucket OAuth. Once the admin moves to Workers/Pages, deployment is viawrangler deployfrom GitHub Actions. The legacy CodeDeploy tooling in the admin UI may be retired rather than ported. - Month-end Excel summary —
Billing::getMonthSummarygenerates an Excel workbook for billing team review. After Stripe transition, the underlying data comes from Stripe. Should this be rebuilt as a Stripe-read report, or replaced by Stripe's native reporting? Needs Jeffrey + Patrick input. - UI component library — shadcn/ui + Radix + Tailwind confirmed as leading candidate. Formally validate against brandguide.adventive.com/dashboard before Phase 1 implementation begins.