# AOLL

**AOLL** is a B2B sales-intelligence platform (ZoomInfo / Winmo class): buying-signal
feeds, advanced company/brand/agency search, intent tracking, alerts, workflow automation,
CRM connectors, and self-serve billing.

Built on **CodeIgniter 4.7.4** (PHP 8.4). The backend and front-end are decoupled: CI4
serves a JSON REST API under `/api`, and a server-rendered front-end consumes it.

> **Current scope: front-end first.** We are building the UI now. The backend/API and all
> third-party integrations (Stripe, Claude, Google OAuth, CRM) are deferred. Pages are
> dynamic, backed by a `MockDataProvider` per domain that returns typed Entities matching
> the future API contracts — so the real backend swaps in later with zero view/controller
> changes. Full detail: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).

---

## Tech stack

| Concern | Choice |
|---|---|
| Framework | CodeIgniter 4.7.4 · PHP 8.4 |
| Database *(Part B)* | MySQL 8 (MySQLi) |
| Auth *(Part B)* | CodeIgniter Shield (email/password, Google, API tokens) |
| Front-end | Bootstrap 5.3.3 + jQuery 3.6 (from the design prototype) |
| Billing *(Part B)* | Stripe |
| AI *(Part B)* | Anthropic Claude API |
| Scheduling *(Part B)* | CI4 Tasks (`spark tasks:run` via cron) |

---

## Getting started

```bash
# 1. install dependencies
composer install

# 2. create your environment file
cp env .env
#    then set:  CI_ENVIRONMENT = development
#               app.baseURL = 'http://localhost:8080/'

# 3. run the dev server
php spark serve
#    → http://localhost:8080
```

**Requirements:** PHP 8.2+ with `intl` and `mbstring` extensions.

---

## Project structure

Standard CI4 tree, organized by **controller namespace + a Services/Entities layer**.
Items marked *(Part B)* are the deferred backend; everything else is the current
front-end scope.

```
aoll/
├── app/
│   ├── Controllers/
│   │   ├── BaseController.php
│   │   ├── MarketingController.php   # front-end: home, pricing, features, about, contact, demo, blog, legal
│   │   ├── AuthPageController.php    # front-end: login, signup, forgot-password (form UI)
│   │   ├── DashboardController.php   # front-end: dashboard: feed, search, company, signals, saved,
│   │   │                             #            alerts, workflows, connectors, plan, users, settings
│   │   └── Api/                      # backend: REST JSON API (/api/v1/*)
│   │       ├── Contracts/
│   │       │   └── RestResourceInterface.php  # index/show/create/update/delete contract
│   │       ├── BaseApiController.php          # ResponseTrait + JSON envelope (ok()/error()); 501 default verbs
│   │       ├── CompanyController.php  BrandController.php   AgencyController.php
│   │       ├── SignalController.php   TopicController.php   FeedController.php
│   │       ├── SavedSearchController.php  AlertController.php  WorkflowController.php
│   │       ├── ConnectorController.php  PlanController.php   UserController.php
│   │       └── FallbackController.php         # JSON 404 for unknown /api/v1/* paths
│   │
│   ├── Services/                     # business logic (thin controllers, fat services)
│   │   ├── SearchService.php         SignalService.php    IntentService.php
│   │   ├── FeedService.php           SavedSearchService.php  AlertService.php
│   │   ├── WorkflowEngine.php        ConnectorService.php
│   │   ├── BillingService.php        EntitlementService.php  UsageService.php   # (Part B)
│   │   ├── AiInsightService.php      NotificationService.php EmailService.php   # (Part B)
│   │   └── Providers/                # data providers behind repository interfaces
│   │       ├── Contracts/            #   CompanyRepositoryInterface, SignalRepositoryInterface, …
│   │       ├── Mock/                 #   MockCompanyProvider, MockSignalProvider, … (current: fixtures)
│   │       └── Api/                  #   ApiCompanyProvider, …                    (Part B: HTTP → /api)
│   │
│   ├── Entities/                     # typed domain objects
│   │   ├── Company.php  Brand.php  Agency.php  Contact.php  Technology.php
│   │   ├── IntentTopic.php  Signal.php  BusinessEvent.php  OutreachRecommendation.php
│   │   ├── SavedSearch.php  Alert.php  Workflow.php  Connection.php
│   │   └── Plan.php  Subscription.php  Invoice.php  User.php  Organization.php
│   │
│   ├── Models/                       # (Part B) CI4 Models — one per table/aggregate
│   │
│   ├── Fixtures/                     # placeholder data feeding the Mock providers (current)
│   │   ├── companies.php  brands.php  agencies.php  contacts.php
│   │   ├── signals.php    topics.php  alerts.php    workflows.php
│   │   └── plans.php      integrations.php
│   │
│   ├── Filters/                      # (Part B) ApiAuthFilter, TenantFilter,
│   │                                 #          EntitlementFilter, RoleFilter, CorsFilter
│   │
│   ├── Database/                     # (Part B) Migrations/ + Seeds/
│   │
│   ├── Config/
│   │   ├── Routes.php                # web routes (App\Controllers) + REST api/v1 (App\Controllers\Api)
│   │   ├── Services.php              # DI — binds RepositoryInterface → Mock provider (swap later)
│   │   ├── App.php  Database.php  Cors.php  Filters.php  …
│   │
│   ├── Helpers/  Language/  Libraries/  ThirdParty/
│   │
│   └── Views/
│       ├── layouts/                  # site.php · dashboard.php · auth.php
│       ├── partials/
│       │   ├── site/                 #   nav.php, footer.php   (was JS-injected → now server-rendered)
│       │   └── dashboard/            #   sidebar.php, header.php, toast.php
│       ├── marketing/                # home, pricing, features/*, about, contact, demo, blog, legal
│       ├── auth/                     # login, signup, forgot
│       ├── app/                      # feed, search, company-details, signals, saved, alerts,
│       │                             # workflows, connectors, plan, manage-subscription, users, settings
│       └── emails/                   # welcome, payment-successful, payment-unsuccessful,
│                                     # subscription-reactivated, signed-up-not-subscribed
│
├── public/
│   ├── index.php                     # front controller
│   ├── assets/                       # ported from the prototype (consolidated, paths via base_url())
│   │   ├── css/                      #   site design tokens (--ea-*) + dashboard tokens (--db-*)
│   │   ├── js/                       #   main.js, dashboard/*, page scripts
│   │   ├── images/                   #   aoll-logo.svg (+ dark), favicons
│   │   └── email/                    #   email-template images (absolute-hosted)
│   └── aoll-design-assets/           # ORIGINAL static prototype (reference — source of the port)
│       ├── *.php                     #   marketing + auth pages
│       ├── dashboard/                #   13 dashboard screens + includes
│       ├── landing/                  #   alternate landing page
│       ├── email-templates/          #   5 HTML email templates
│       └── assets/                   #   prototype css/js/images
│
├── docs/
│   └── ARCHITECTURE.md               # full architecture plan (data model, routes, roadmap)
│
├── tests/                            # PHPUnit
├── writable/                         # cache, logs, sessions, uploads (git-ignored)
├── system/                           # CodeIgniter framework core (do not edit)
├── spark                             # CLI entry point (php spark …)
├── composer.json
├── env                               # template → copy to .env
└── README.md
```

---

## Front-end data flow (current phase)

Pages are dynamic but data is mocked, behind a repository interface so the backend swaps
in with no view/controller changes:

```
View  ←  Web Controller  ←  CompanyRepositoryInterface
                                 ├─ now:   MockCompanyProvider  → app/Fixtures
                                 └─ later: ApiCompanyProvider    → GET /api/v1/companies   (Part B)
```

The binding lives in `app/Config/Services.php`. Swapping Mock → Api is a one-line change
per domain.

---

## Route separation

| Prefix | Serves | Status |
|---|---|---|
| `/` , `/login`, `/pricing`, `/app/*`, … | server-rendered front-end pages (`App\Controllers`) | **current** |
| `/api/v1/*` | REST JSON API (`Api`) — read endpoints live off the Mock providers; write verbs return 501 until the backend phase | **current (read)** |

REST API responses use a consistent envelope — `{ "status": "success", "data": …, "meta": … }`
on 2xx and `{ "status": "error", "message": …, "errors": … }` on 4xx/5xx — with proper
HTTP status codes (200 / 404 / 501). Every resource controller implements
`RestResourceInterface` and extends `BaseApiController`.

---

## Build roadmap

**Part A — Front-end (current):** A0 Foundation → A1 Mock data layer → A2 Auth & shell →
A3 Search & company detail → A4 Signals & feed → A5 Alerts/workflows/saved/connectors →
A6 Billing & team → A7 Marketing site.

**Part B — Backend (deferred):** `/api/v1` + Shield auth, MySQL schema, provider swap,
entitlements, then integrations (Stripe / Claude / Google / CRM) and the Enterprise API.

See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full breakdown, and
[docs/TODO.md](docs/TODO.md) for the running task backlog (everything still to do).

---

## Design reference

The complete UI prototype (marketing site, auth, all 13 dashboard screens, 5 email
templates) lives in [public/aoll-design-assets/](public/aoll-design-assets/) and is the
source of truth for the port. It uses Bootstrap 5.3 with two independent design-token
sets — site (`--ea-*`) and dashboard (`--db-*`).
