7.6 KiB
| title | description | tags | created | updated | ||
|---|---|---|---|---|---|---|
| Client Knowledge: Barclays | Barclays-specific context: projects, tech constraints, deployment quirks, and lessons learned |
|
2026-04-27 | 2026-04-28 |
Client Knowledge: Barclays
Key Takeaways
- Two active projects: Mod Comms (GCP, multi-agent AI) and Banner Builder (optical-dev, React+FastAPI)
- Barclays requires strict brand compliance — logo versions matter, Barclays design tokens used in UI
- GCP deployment = no WebSockets — REST polling is mandatory for Mod Comms
- Banner Builder uses Zustand for workflow state management (journey store pattern)
Projects
| Project | Server | Stack | Status | Purpose |
|---|---|---|---|---|
| 01 Projects/modcomms/Mod Comms | GCP | FastAPI + React + Gemini + PostgreSQL | active | AI proof review — compliance/brand/tone/channel checks |
| 01 Projects/Barclays-banner-builder/Barclays Banner Builder | optical-dev | FastAPI + React + PostgreSQL + Docker | active | AI banner generation tool — Brief → Variants → Edit → Export |
Mod Comms — Key Facts
What it does: Upload proof (image/PDF) → 4 AI agents analyze in parallel → lead agent synthesizes verdict
4 agents: Legal compliance, Brand adherence, Tone of Voice, Channel suitability
AI: Google Gemini Pro (primary) + Flash (fallback) — chosen for GCP co-location
Critical incident (2026-03-18): WebSocket connections dropped at 30s on GCP LB → switched to REST polling. See wiki/architecture/gcp-deployment-lb-timeout.
Auth: Azure AD (MSAL) — uses DISABLE_AUTH=true locally
Dev start:
# Backend
cd backend && uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# Frontend
cd frontend && npm install && npm run dev
# DB migrations
cd backend && alembic upgrade head
Env vars (backend):
GEMINI_API_KEY=
DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/modcomms
AZURE_TENANT_ID=
AZURE_CLIENT_ID=
DISABLE_AUTH=true
Banner Builder — Key Facts
What it does: AI-assisted banner creation. Workflow: Brief → Edit Variants → Banner Editor → Export CSV/PDF
Workflow state: Managed with Zustand journey store — backward navigation allowed, forward steps grayed out until completed. See wiki/concepts/export-endpoint-filter-pattern.
Export quirk: PDF/CSV exports must receive variant_ids from frontend — backend cannot infer selection. Always pass explicitly.
Deploy: optical-dev at /barclays-banner-builder/ subpath. Deploy via bash deploy.sh on server.
Apache config: Barclays Include fragment at /opt/barclays-banner-builder/deploy/apache-barclays.conf. Port: 8010.
Critical incident (2026-04-17): Apache Include directive ordering — Banner Builder's conf was loading after hp-prod-tracker's catch-all ProxyPass / http://..., which intercepted all requests. Fixed by reordering Include lines in vhost config.
Stack:
- Frontend: React + TypeScript + Vite + Zustand
- Backend: FastAPI + Python + Alembic + PostgreSQL
- Auth: Azure AD (MSAL)
- Deploy: Docker Compose + Apache subpath
Brand Requirements
- Logo versions matter — track which version is active (
v4,v5,v6) - Barclays design tokens used in UI (Zustand journey stepper used Barclays color tokens)
- Export outputs go to OMG media booking system — format must be exact
Banner Builder UI Rebrand (2026-04-28)
The banner builder UI was rebranded from the Barclays design system to the Oliver Modcomms design system. Visual layer changed; core functionality unchanged.
What changed:
- Tailwind tokens renamed from
barclays-*→oliver-* - Layout: horizontal nav → dark vertical sidebar (
w-[220px]), matching the Modcomms pattern - Theme colour picker added to both
BannerEditorandVariantsGridviews; variants have athemeenum:navy | sky-blue | yellow | lime | teal - Logo: placeholder
CopyGenBannerAgent_RFA.pnggenerated viasips(PIL not available on macOS); real CopyGen/Oliver asset needed
What did NOT change (by design):
- Internal localStorage key names (
barclays-*) intentionally kept to avoid invalidating in-flight user sessions — see wiki/concepts/localstorage-key-migration-rebrand for why and how to handle this in a future release - AI Refine/Improve box only mutates copy text fields — cannot change visual theme/colours (by architecture)
- Barclays brand hex codes (
#00AEEF,#00395D, etc.) remain correct intailwind.config.tsas of commit47b3f12
Lessons from banner-builder (2026-04-28)
QA session on barclays-banner-builder surfaced three non-obvious bugs. All three share a common trait: they fail silently rather than throwing a clear error.
DB Seed Silent Skip
Seed scripts using INSERT IF NOT EXISTS or get_or_create silently skip existing rows. If a test/demo user was created before the seed ran (e.g., with a different password), the seed never updates it. Auth fails at login with no error in logs — the user row simply has the wrong password.
Fix: Always verify actual DB state when auth fails unexpectedly after seeding:
SELECT email, created_at FROM users WHERE email = 'seed@example.com';
-- If it exists with old data, DELETE and re-run seed, or UPDATE manually
Zustand Async Hydration Bug
ConversationLanding fired an API call on mount before the Zustand auth store had hydrated from localStorage. On first render, token was null (initial state) → API call sent without auth header → 401 → redirect to login, even though the user was logged in.
Fix: Gate all auth-dependent API calls behind hasHydrated:
const { token, hasHydrated } = useAuthStore()
useEffect(() => {
if (!hasHydrated) return
fetchData()
}, [hasHydrated, token])
See wiki/concepts/zustand-async-hydration for full pattern.
Pydantic Model/Dict Interface Bug in tasks.py
refine_variant_copy Celery task was written to accept a dict but was called with a BannerCopy Pydantic model. Every .get("field") call on the Pydantic object returned None silently — the task continued running with all-null inputs, hanging the AI refinement pipeline without raising an exception.
Fix: Convert at call site: task.delay(banner_copy.model_dump(), ...) or update the function to accept the Pydantic model directly.
See wiki/concepts/pydantic-model-dict-interface for full pattern.
LoginPage Hardcoded Redirect
LoginPage had a hardcoded redirect to /brief instead of / in the auth success handler. This caused the entire post-login flow to break for users who should land on the home route. Always use a configurable redirect target (e.g., location.state?.from or a constant) rather than a hardcoded path.
Related
- wiki/architecture/gcp-deployment-lb-timeout — WebSocket → REST polling
- wiki/architecture/optical-dev-server-deploy — Banner Builder deployment
- wiki/tech-patterns/python-ai-agents — multi-agent pattern used in Mod Comms
- wiki/concepts/export-endpoint-filter-pattern — variant_ids in exports
- wiki/concepts/zustand-async-hydration — Zustand hydration timing bug (Banner Builder)
- wiki/concepts/pydantic-model-dict-interface — Pydantic vs dict silent failure (Banner Builder tasks.py)
- wiki/concepts/localstorage-key-migration-rebrand — localStorage key migration after rebrand (Banner Builder 2026-04-28)