ForeignX Drops — Architecture¶
Plain twin: ../business-plain/business-overview.md
Layout (USPTO-shaped backend + Angular UI)¶
ForeignXDrops.slnx
src/ForeignXDrops/ # ASP.NET Core 8 (Cloud Run)
Controllers/ # Auth, Lists, Users, Metrics, Organizations, Engagement
Services/ + Interfaces/ # X API, Sheets, KeePass, Drop orchestration, orgs, cards
Models/ + Enums/ + Jobs/ # Domain + Quartz
Configuration/ # AppSettings
tests/ForeignXDrops.Tests/
frontend/src/app/ # Angular (USPTO-UI-style components/services/models)
components/ # dashboard, admin-panel, metrics, engagement-cards
services/
models/
Multi-tenant¶
- Organization = one influencer group (slug, plan, timezone, default
EngagementMode). - Users and drops carry
OrganizationId. - v1 org registry: process-local (
OrganizationService). Next: Organizations sheet + org-prefixed tabs / per-org spreadsheet id. - KeePass: plan
orgs/{organizationId}/…group path (not fully wired).
Engagement modes¶
Stored on DropList.EngagementMode at create time:
| Mode | Auto like/repost | Manual cards |
|---|---|---|
| Automatic | yes | no |
| Manual | scrape only | yes |
| Both | yes | yes |
Cards: GET /api/engagement/{listId}/cards, POST .../actions (Like/Repost/Skip/OpenInX) using member KeePass token.
X API (Flurl + Polly)¶
OAuth2 PKCE, lists, members, likes, reposts, DMs, optional tweet metrics. App bearer for list create/scrape; user bearer for engagement.
Google Sheets¶
Users / Lists / per-list tweet tabs (existing design). Org scoping is the next persistence step.
KeePass¶
Bearer tokens only; Sheets hold timestamp. KPScript (+ Mono on Linux). GCS sync for Cloud Run ephemeral disk.
Scheduling¶
Quartz: daily list create, engagement run, metrics DMs. Cloud Run min instances ≥ 1 so the host is not scaled to zero between jobs.
Deploy¶
Multi-stage Dockerfile → Cloud Run. PORT env, CORS_ORIGINS, no HTTPS redirection in container.