Project Tracker
Single-page status of the SalesArck build. Updated when implementation lands or shifts; the source of truth is the salesarck monorepo.
Status icons: ✅ shipped · 🟡 partial / behind a feature flag · 🔴 not started · 🧪 experimental · 🔧 known gap
Each status item links to the implementation file (or the doc that explains it) so you can verify it without leaving the page.
Snapshot
| Layer | Status | Notes |
|---|---|---|
| API runtime (Hono) | ✅ Shipped | 8 route groups mounted at /api/v1/* |
| Database schema (Drizzle) | ✅ Shipped | 13 tables + indices; managed via drizzle-kit push |
| Auth (Supabase OTP + PKCE) | ✅ Shipped | Email + phone OTP, role-aware redirect |
| RBAC | ✅ Shipped | 17 permissions, 4 roles (consumer/client/pos_operator/admin) |
| Tenant isolation | ✅ Shipped | tenantMiddleware + scoped queries |
| Square integration | ✅ Shipped | OAuth + webhook + cron poll fallback |
| Clover integration | ✅ Shipped | OAuth + webhook + REST payment fetch (no poll fallback) |
| Reward engine | ✅ Shipped | Pure, deterministic, fully tested |
| Wallet ledger | ✅ Shipped | Append-only, atomic credit/debit |
| Redemption codes (consumer + POS operator) | ✅ Shipped | 6-byte hex, 15-min TTL, single-use |
| Admin tooling (approve users, freeze/adjust wallets, audit log) | ✅ Shipped | All actions write admin_audit_logs |
| Email notifications (Resend) | ✅ Shipped | Points-earned + redemption-code emails |
| Webhook retry sweeper | ✅ Shipped | /internal/cron/process-pending-webhooks |
| Workers app | 🟡 Scaffolded | apps/workers/src/index.ts is currently a logging stub; cron jobs run via Render scheduler hitting cron routes |
| Idempotency-key TTL cleanup | 🔧 Gap | expires_at stored but lookup ignores it; no cleanup job (details) |
| Clover poll fallback | 🔧 Gap | Recovery relies on webhook retry sweeper |
| Reconciliation jobs | 🔴 Not started | No automated ledger reconciliation |
| Campaign multipliers | 🟡 Stubbed | Hardcoded 1 in ingestion path |
Backend Surface (apps/api)
Routes
| Group | Mount | File | Status |
|---|---|---|---|
| Auth | /api/v1/auth | routes/auth.ts | ✅ |
| Consumer | /api/v1/consumer | routes/consumer.ts | ✅ |
| Client (merchant) | /api/v1/client | routes/client.ts | ✅ |
| Admin | /api/v1/admin | routes/admin.ts | ✅ |
| POS operator | /api/v1/pos | routes/pos.ts | ✅ |
| Webhooks | /api/v1/webhooks | routes/webhooks.ts | ✅ Square + Clover |
| OAuth callbacks | /api/v1/oauth | routes/pos-oauth.ts | ✅ Square + Clover |
| Internal cron | /api/v1/internal/cron | routes/cron.ts | ✅ Square poll + webhook sweeper |
Full route table → API Reference.
Services
| Service | File | Status |
|---|---|---|
| Ingestion (provider-agnostic core) | services/ingestion.ts | ✅ |
| Wallet credit / ledger | services/wallet-service.ts | ✅ |
| Square adapter | services/square-adapter.ts | ✅ |
| Square API client | services/square-api.ts | ✅ |
| Square poll worker | services/square-poll.ts | ✅ |
| Clover adapter | services/clover-adapter.ts | ✅ |
| Clover API client | services/clover-api.ts | ✅ |
Middleware
correlation → db → auth (or auth-profile) → tenant → rbac.requirePermission(...). Order is enforced in app.ts. All middleware shipped.
Frontend Surface (apps/web)
Pages
| Route | Component | Roles | Status |
|---|---|---|---|
/login | LoginPage | public | ✅ |
/auth/callback | AuthCallbackPage | public | ✅ |
/profile-error | ProfileErrorPage | all (post-auth) | ✅ |
/pending-approval | PendingApprovalPage | all | ✅ |
/account-blocked | AccountBlockedPage | all | ✅ |
/onboarding | OnboardingPage + MerchantProfileWizard | client | ✅ |
/dashboard | DashboardPage (Client/Admin views) | client, admin | ✅ |
/rewards | RewardConfigPage | client, admin | ✅ |
/pos | PosSettingsPage | client, admin | ✅ |
/store-operators | StoreOperatorsPage | client | ✅ |
/transactions | TransactionsPage | client, admin | ✅ |
/wallet | WalletPage | consumer | ✅ |
/history | HistoryPage | consumer | ✅ |
/redeem | RedeemPage (+ PosOperatorRedeemPanel) | consumer, pos_operator | ✅ |
/profile | ProfilePage (role-dispatched) | all | ✅ |
/admin/tenants | TenantsPage | admin | ✅ |
/admin/users | UsersPage | admin | ✅ |
/admin/audit-logs | AuditLogsPage | admin | ✅ |
Routing details → Frontend Architecture.
Frontend infrastructure
| Concern | Status |
|---|---|
| React 18 + Vite 5 + React Router 6 | ✅ |
Supabase JS (PKCE flow, session in sessionStorage) | ✅ |
| Zustand auth store | ✅ |
apiFetch<T>() with bearer auth + retry/backoff | ✅ |
| TanStack Query installed | 🟡 Configured but not heavily used |
| Tailwind CSS | ✅ (existing code); guideline: no Tailwind in new code (use ui.tsx primitives) |
ui.tsx primitives (Icon, Avatar, Brandmark, StatusPill, KV, MerchantMark) | ✅ |
Data Model
13 tables in packages/db/src/schema/index.ts. All shipped:
| Table | Append-only? | Purpose |
|---|---|---|
users | No | Profile mirror of Supabase auth |
tenants | No | Merchant org |
tenant_users | No | User ↔ tenant membership + role |
pos_connections | No (status flips) | Encrypted Square/Clover OAuth tokens |
pos_webhook_events_raw | Yes | Raw payloads for fast-ack + retry |
transactions | Yes | Canonical normalized POS transaction |
wallets | No (balance snapshot) | One per (tenant, user) |
wallet_ledger | Yes — never UPDATE/DELETE | Source of truth for points |
redemption_codes | No (status flips pending → used) | Single-use, 15-min TTL |
tenant_operator_invites | No (status flips) | Pre-authorized store-operator emails |
reward_rules | Yes (versioned) | Tenant reward configuration |
reward_events | Yes | Audit link tx → wallet earn/redeem |
idempotency_keys | Yes | Mutation deduplication (cleanup job pending) |
admin_audit_logs | Yes — immutable | Privileged action trail |
Full schema → Data Model and Migrations.
Workers / Background Jobs
| Job | How it runs today | Status |
|---|---|---|
Square ListPayments poll | Render cron → POST /internal/cron/square-poll-payments | ✅ |
| Webhook retry sweeper | Render cron → POST /internal/cron/process-pending-webhooks | ✅ |
| Token refresh | Inline during poll (180s buffer ahead of expiry) | ✅ |
| Email send (Resend) | Fire-and-forget from request handler | ✅ |
| Idempotency-key TTL cleanup | — | 🔧 Gap (no cleanup) |
| Clover poll fallback | — | 🔧 Gap (sweeper covers retry) |
| Ledger reconciliation | — | 🔴 Not started |
| Queue-backed worker (Cloudflare Queues / BullMQ) | — | 🔴 apps/workers is a logging stub |
Packages
| Package | Status | Notes |
|---|---|---|
@salesarc/types | ✅ | Foundation; Zod schemas + TS types |
@salesarc/db | ✅ | Drizzle schema + client |
@salesarc/auth | ✅ | Supabase server-side auth helpers |
@salesarc/rbac | ✅ | Permission enum + hasPermission |
@salesarc/tenant | ✅ | Membership resolver + admin bypass |
@salesarc/reward-engine | ✅ | Pure points calculation |
@salesarc/observability | ✅ | Pino + Sentry + correlation IDs |
Deployment
| Surface | Target | Status |
|---|---|---|
| Frontend | Vercel (salesarc-web.vercel.app) | ✅ |
| API | Render (salesarc-api.onrender.com) | ✅ |
| Database | Supabase Postgres | ✅ |
| Auth | Supabase Auth (OTP, PKCE) | ✅ |
| File storage (logos) | Supabase Storage | ✅ |
| CI/CD | GitHub Actions | ✅ |
| Documentation site | Cloudflare Pages | ✅ |
Known Gaps and Hardening Backlog
These are tracked from code-level TODOs and docs/code/* "Known gaps" sections.
- Idempotency-key cleanup —
expires_atis stored but ignored at lookup time; no cleanup job. Acts as permanent dedup until addressed. (ingestion docs) - Idempotency replay snapshots —
idempotency_keys.result_snapshotis not yet returned to callers. - Clover polling fallback — recovery for failed Clover webhooks goes through the retry sweeper rather than a
ListPayments-equivalent. - Campaign multipliers — ingestion uses a hardcoded
1; tenant campaign config is not yet a first-class concept. - Reconciliation jobs — no automated
SUM(ledger) ?= wallet.balanceaudit. - Workers app is a stub — queue consumer, ingestion-worker, and dedicated token-refresh-worker are TODOs in
apps/workers/src/index.ts. - Redemption code verification — server-side flow is solid; richer POS-operator UX (history, filtering, refund) is intentionally minimal in the current phase.
- Tenant admin email — admin role is gated to
@doshidhruv.com; multi-org admin is not yet supported.
Roadmap Pointers
- Product roadmap — phase-level delivery plan
- Risks register
- Architecture overview
- Code documentation index — implementation reference
How to update this page
When a piece of work lands:
- Flip the relevant ✅ / 🟡 / 🔴 status above
- Move any closed gap from Known Gaps to the Snapshot table (or remove it)
- Add a one-line link to the implementation file or doc that proves it
- Commit alongside the implementing PR (
docs(tracker): ...)
Keep entries short — this is an index, not a changelog. Detailed history lives in git and docs/code/git-evolution.md.