Files
reseller-platform/CONTRACT.md
2026-08-25 20:02:23 -07:00

5.3 KiB

Polaris — Reseller Platform · Module Contract (agents read this)

Single source of truth for the 3 parallel build agents. Do NOT drift from these interfaces — the other agents depend on them exactly as written.

Stack (locked)

  • Backend: FastAPI (Python 3.12) in /backend, SQLAlchemy 2.0 ORM, Pydantic v2
  • DB: PostgreSQL 16 (schema in db/schema.sql — DO NOT modify it, build against it)
  • Queue: Celery + Redis (redis://redis:6379/0)
  • Frontend: React 18 + Vite + TypeScript + Tailwind in /frontend
  • Deploy: Docker Compose (root docker-compose.yml already has postgres+redis)

Service URLs (inside Docker network)

  • postgres: postgres://reseller:${POSTGRES_PASSWORD}@postgres:5432/reseller
  • redis: redis://redis:6379/0
  • api listens on 0.0.0.0:8000

BACKEND agent owns: /backend

  • app/main.py — FastAPI app, CORS allow-all (MVP), mounts routers under /api
  • app/models.py — SQLAlchemy models mirroring db/schema.sql EXACTLY (table + column names)
  • app/database.py — engine from DATABASE_URL env, SessionLocal, Base
  • app/schemas.py — Pydantic v2 request/response models
  • app/engines/pricing.py — calculate_price(cost, shipping, fees) -> returns retail, margin, profit using active price_rules; estimate_net_profit(...); never below min_price
  • app/engines/suppliers/base.py — SupplierAdapter ABC: get_products / get_inventory / get_price / create_order / get_order_status / get_tracking / cancel_order
  • app/engines/suppliers/csv_adapter.py — CSV feed adapter (reads supplier CSV: sku,title,cost,inventory,shipping_cost,shipping_time,category,image_url)
  • app/engines/suppliers/sample.py — sample supplier seeded with ~25 realistic products ($50-$500, home/gadgets/office niche)
  • app/engines/importer.py — import feed -> normalize -> validate -> upsert products/supplier_products; never auto-publish invalid
  • app/engines/order_router.py — select_supplier(product_id, qty) highest-score eligible supplier; route_order(order)
  • app/engines/scoring.py — supplier score = 40% price + 20% inventory + 15% speed + 10% fulfillment + 10% returns + 5% history
  • app/engines/inventory.py — sync supplier_products inventory, mark 0/unavailable, alert flags
  • app/tasks.py — Celery: sync_inventory (every 5min), sync_tracking, recalc_prices
  • app/routers/ — products.py, suppliers.py, orders.py, customers.py, admin.py, analytics.py, health.py
  • alembic/ — optional; MVP may Base.metadata.create_all() instead (schema.sql is canonical)

API endpoints (frontend depends on these — do not rename)

  • GET /api/health -> {status, version}
  • GET /api/products (filters: ?status=&category=&search=&limit=&offset=)
  • GET /api/products/{id}
  • POST /api/products/{id}/publish
  • POST /api/products/{id}/pause
  • GET /api/products/{id}/price-history
  • POST /api/products/import (body: {supplier_id, feed_type, data_or_url})
  • GET /api/suppliers / POST /api/suppliers
  • GET /api/suppliers/{id}/performance
  • POST /api/orders (body: {customer_email, items:[{product_id,qty}]}) -> creates+routes order
  • GET /api/orders / GET /api/orders/{id}
  • POST /api/orders/{id}/tracking (simulate supplier tracking push)
  • GET /api/analytics/summary -> today revenue/orders/profit/margin/aov/conversion
  • GET /api/analytics/top-products
  • GET /api/analytics/supplier-performance
  • POST /api/auth/login (admin, simple: env ADMIN_EMAIL/ADMIN_PASSWORD_HASH, returns JWT)
  • POST /api/auth/register (customer)

FRONTEND agent owns: /frontend

React+Vite+TS+Tailwind. Two surfaces, shared API client (src/lib/api.ts):

  • / storefront: home, shop grid, category filter, product page, cart, checkout (mock Stripe/BTCPay button -> creates order), order-tracking page. ORIGINAL brand "Polaris". Dark premium aesthetic. BMAC footer link https://buymeacoffee.com/r26xrthzttg
  • /admin dashboard: today KPI cards (revenue/orders/gross+net profit/margin/aov/refunds), top products table, supplier performance table, import button, product lifecycle view, order list with status + tracking. Cache-Control no-store on all API fetches.
  • Env: VITE_API_URL=/api (nginx proxies).

OPS agent owns: root deploy + docs

  • Extend docker-compose.yml with: api, worker, frontend, nginx services
  • backend/Dockerfile, frontend/Dockerfile, nginx/nginx.conf (proxy /api->api:8000, /->frontend)
  • .env.example (POSTGRES_PASSWORD, DATABASE_URL, REDIS_URL, SECRET_KEY, ADMIN_EMAIL, ADMIN_PASSWORD, BTCPAY_URL/KEY, STRIPE_KEY)
  • README.md (deploy steps), docs/api.md (endpoint reference), tests/ (pytest smoke tests)
  • systemd unit polaris.service wrapping docker compose up -d, enabled+started

Verification (the parent re-runs these — every agent must self-verify first)

  1. docker compose up -d clean, all containers healthy
  2. seed sample supplier + import -> products appear in GET /api/products
  3. pricing returns sensible margin for a $80 cost item
  4. POST /api/orders creates order, routes to supplier, records profit
  5. frontend / and /admin render with live API data
  6. README deploy steps reproducible from scratch

Rules

  • Secrets ONLY via env vars, never hard-coded.
  • Backup any existing file before overwriting (cp x x.bak-).
  • Never delete the parent's work; only add/extend.
  • All code self-contained; report exact files changed + live curl proof.