Records what Phase 1 does and deliberately does not do: no Meta writes, no launch or sync endpoint, previews rendered without creating objects, budget minimums enforced locally, and the fact that a payment method can only be attached in Meta Business Manager. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
172 lines
6.2 KiB
Markdown
172 lines
6.2 KiB
Markdown
# MaskanX Backend
|
|
|
|
Independent Python and FastAPI backend for MaskanX.
|
|
|
|
## Service Contract
|
|
|
|
- Default API URL: `http://127.0.0.1:8088`
|
|
- PostgreSQL database: `campaign`
|
|
- Frontend origin: configured with `MASKANX_CORS_ORIGINS`
|
|
- Maskan CRM: connected through its versioned REST API and optional MCP tools
|
|
|
|
This repository never connects directly to the Maskan CRM PostgreSQL database.
|
|
|
|
## Local Setup
|
|
|
|
1. Create the database:
|
|
|
|
```sql
|
|
CREATE DATABASE campaign;
|
|
```
|
|
|
|
2. Install dependencies and configure the environment:
|
|
|
|
```powershell
|
|
python -m venv .venv
|
|
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
|
|
npm install
|
|
Copy-Item .env.local.example .env.local
|
|
```
|
|
|
|
3. Migrate, seed, and start:
|
|
|
|
```powershell
|
|
npm run local:migrate
|
|
npm run local:seed
|
|
npm run local
|
|
```
|
|
|
|
Open API documentation at `http://127.0.0.1:8088/docs` when documentation is
|
|
enabled.
|
|
|
|
### Upgrading from JSON storage
|
|
|
|
Chats and cron jobs were originally stored as JSON files in the working
|
|
directory (`~/.adclaw/chats.json` and `~/.adclaw/jobs.json`). PostgreSQL is now
|
|
the default backend, so those records are no longer read and existing chats,
|
|
sessions, and scheduled jobs appear to be missing even though nothing was
|
|
deleted.
|
|
|
|
Copy them into PostgreSQL once:
|
|
|
|
```powershell
|
|
npm run local:import-json -- --dry-run # report what would be imported
|
|
npm run local:import-json # perform the import
|
|
```
|
|
|
|
The import upserts by id and never deletes, so it is safe to re-run. The JSON
|
|
files are left untouched as a backup.
|
|
|
|
## Campaigns
|
|
|
|
Campaign records live in PostgreSQL. Apply the schema before first use:
|
|
|
|
```powershell
|
|
npm run local:migrate
|
|
```
|
|
|
|
Set `META_ADS_ACCESS_TOKEN` in Settings > Environments, and enable the
|
|
`meta_ads` MCP client if you also want campaign tools in chat.
|
|
|
|
### What Phase 1 does and does not do
|
|
|
|
Phase 1 owns campaign records, the approval workflow, budget guardrails and ad
|
|
preview. **It creates nothing in Meta.** The only Meta calls are two reads:
|
|
|
|
- `GET /act_<id>` for balance, spend and `min_daily_budget`
|
|
- `GET /act_<id>/generatepreviews` to render ad previews
|
|
|
|
There is deliberately no launch or sync endpoint. A campaign moves
|
|
`draft -> pending_approval -> approved` and stops there; pushing objects to
|
|
Meta arrives in Phase 2.
|
|
|
|
Ad previews are rendered from a creative spec and create no Meta objects, so
|
|
the wizard can show exactly how an ad will look across desktop feed, mobile
|
|
feed, Instagram feed, Instagram story, Facebook story and right column before
|
|
anything exists.
|
|
|
|
### Budget minimums
|
|
|
|
Each ad account publishes a `min_daily_budget` in minor units. The API rejects
|
|
a lower daily budget with `422` and a readable message rather than letting Meta
|
|
reject it opaquely later. If the account cannot be read (no token, rate limit),
|
|
the check is skipped and a warning is logged: the budget guardrail is not
|
|
enforced in that case.
|
|
|
|
### Delivery requires a payment method
|
|
|
|
Meta will not deliver ads until a funding source is attached to the ad account.
|
|
**This cannot be done from MaskanX** — the Marketing API does not allow
|
|
creating funding instruments, so it must be done in Meta Business Manager. The
|
|
Campaigns page shows a warning when no payment method is present.
|
|
|
|
### Clearing and restoring credentials
|
|
|
|
**Stop MaskanX before clearing credentials.** A running app holds its
|
|
configuration in memory and can rewrite `config.json` and `providers.json`
|
|
after the clear, silently restoring the values that were just removed. The
|
|
clear script now verifies the result and exits non-zero if anything
|
|
secret-looking survives.
|
|
|
|
Credentials live in three places, and all of them are cleared:
|
|
|
|
- `~/.adclaw.secret/providers.json` - LLM provider keys
|
|
- `~/.adclaw.secret/envs.json` - integration keys
|
|
- `~/.adclaw/companies/<id>/` - a per-company copy of both, plus LinkedIn OAuth
|
|
|
|
Because each company keeps its own copy, an intact company store can be used to
|
|
recover the active one:
|
|
|
|
```powershell
|
|
npm run secrets:restore -- --from default --dry-run
|
|
npm run secrets:restore -- --from default
|
|
```
|
|
|
|
Credential files are copied wholesale; `config.json` is patched surgically, so
|
|
only missing MCP env values and disabled clients are restored and
|
|
company-specific settings are preserved. A backup is written to
|
|
`~/.adclaw.secret/restore-backups/` first.
|
|
|
|
## Commands
|
|
|
|
| Command | Purpose |
|
|
| --- | --- |
|
|
| `npm start` | Start using `.env` or injected environment variables |
|
|
| `npm run build` | Build a Python wheel in `dist/` |
|
|
| `npm run local` | Local API with reload |
|
|
| `npm run local:migrate` | Apply local PostgreSQL migrations |
|
|
| `npm run local:migrate:undo` | Roll back the newest migration |
|
|
| `npm run local:migrate:undo:all` | Roll back every migration |
|
|
| `npm run local:seed` | Add starter data |
|
|
| `npm run local:seed:undo` | Remove starter data |
|
|
| `npm run local:import-json` | Import legacy JSON chats/cron jobs into PostgreSQL |
|
|
| `npm run secrets:dry-run` | Report which credentials a clear would remove |
|
|
| `npm run secrets:clear` | Clear runtime credentials (creates a backup) |
|
|
| `npm run secrets:clear:all` | Also blank secret lines in `.env` files (creates a backup) |
|
|
| `npm run secrets:delete:all` | Clear everything including `.env` files (creates a backup) |
|
|
| `npm run secrets:delete:all:no-backup` | Same, with **no backup** - irreversible |
|
|
| `npm run secrets:restore` | Restore credentials from an intact company store |
|
|
| `npm run local:reset` | Rebuild and seed the local schema |
|
|
| `npm run dev` | Development API with reload |
|
|
| `npm run dev:migrate` | Apply development migrations |
|
|
| `npm run dev:reset` | Reset the development schema |
|
|
| `npm test` | Run Pytest using `.env.testing` |
|
|
| `npm run test:migrate` | Apply test database migrations |
|
|
| `npm run test:reset` | Reset the test schema |
|
|
| `npm run prod` | Start the production API |
|
|
| `npm run prod:migrate` | Apply production migrations |
|
|
| `npm run prod:seed` | Apply production starter data |
|
|
|
|
The command names match the platform deployment contract. They invoke the
|
|
native MaskanX Python migration runner, not Sequelize.
|
|
|
|
## Docker
|
|
|
|
```powershell
|
|
Copy-Item .env.local.example .env
|
|
docker compose up -d --build
|
|
```
|
|
|
|
For a managed PostgreSQL deployment, provide `DATABASE_URL` through the hosting
|
|
secret manager and run `npm run prod:migrate` as a release step.
|