Status
What's complete, what's partial, what's deliberately deferred, and risks
What's complete
- Deterministic matching engine. Reach/Fit/Safety + nine personalized rails + chip-rail pool switcher (For You, Trade, 2-year, Online, All).
- Live Scorecard ingestion with cache. Monthly refresh cron + per-school on-demand fetch.
- AI blurb with anti-slop guardrails.
gpt-5.4-nano+ 30-day cache + graceful degrade on failure. - Structured profile (academics, test scores, finances, background, story, achievements, extracurriculars, community service) with completion-percentage UI.
- Saved-list as a portfolio (every save tagged Reach/Fit/Safety at save time; sortable by category, distance, cost, admit chance).
- WorkOS AuthKit integration end-to-end on mobile + web. Docs site is public + noindex.
- Account deletion cascade through every user-scoped table with workflow-component prune.
- Dark mode across mobile; design tokens generated once for both apps.
- i18n catalogs wired (English fully covered; second-language is a translation pass).
- Push notifications: deadline reminders (14/7/3/1 days out), weekly new-matches alert, in-app profile-completion nudges.
- PostHog product analytics including GDPR erasure path.
- EAS staging + production profiles + ASC + Play Console automation via
asc/gplay. - Marketing website on Vercel — home, About, Contact, privacy/terms, account-deletion request.
- Operational runbooks: add-college-field, backfill-college-data, invalidate-college-cache, categorize-school.
What's partially complete
- Trade-school deep integration. Trade chip rail ships; per-program apprenticeship data + trade-specific outcome views are wired at the data layer but the UI surface is shallow.
aggregateWorkforce+aggregateTransferOutcome. Registered Convex aggregate component instances, used for some queries; full cutover fromby_active_scoreindex is deferred.- Diversity slider. Backend wiring exists; UI is hidden pending design review.
- Sentry. Wired in (
@sentry/nextjs,@sentry/react-native). DSN is blank — turn on by settingNEXT_PUBLIC_SENTRY_DSN+EXPO_PUBLIC_SENTRY_DSN. - R2 + Resend. Provisioned but not in any active production path.
What's deliberately deferred (V2 design choices)
These are NOT bugs. The decision and the reason are recorded so anyone touching the area has context before reopening them.
- Web product surface. The website is marketing-only. Mobile-first was deliberate — web product would add a second deploy target, a second auth surface to harden, and a second design system to maintain. Real demand from analytics should drive any reversal.
- Campus-setting quiz reduction. V1 asked about sunshine, snowfall, religious affiliation, sports division, Greek life. V2 cut to four dimensions that actually drive matching (setting, size, walkability, politics). Easy to add back if user signal demands.
- In-app chat with counselors. Discussed; not built. Would require live moderation + escalation flow + GDPR review of conversation storage.
- Application tracking (Common App integration, submission status). Deadline reminders ship; submission tracking does not.
- District / school admin dashboards. Aligned with the South University and Florida district pipeline. Consumer-only today; an admin surface is net-new work.
- Second language. i18n is wired. Adding Spanish is a translation file + a few RTL/LTR-agnostic checks, not engineering work.
- A dedicated staging Convex deployment. Operator-burden trade-off — see Deployment.
- CI deploys for backend. Local-machine deploy works today. Move to GitHub Actions once more than one person deploys regularly.
- Convex outbound backups. Convex internal snapshots are the recovery story. Configure S3/R2 exports via the Convex dashboard for defense-in-depth (~30 minutes).
Known technical debt
by_active_scoreindex is the legacy sort path. Two aggregate components (aggregateWorkforce,aggregateTransferOutcome) are intended to replace it. Live inconvex/schema.tscomments.collegestable usesv.any(). Trade-off documented in Data. All reads must go throughlib/collegeShape.tshelpers; lint does not enforce this.discover.railsquery loads all nine rails in a single round-trip. Per-rail split is noted in code as a post-launch performance optimization once mobile usage justifies it.- No frontend integration test of the OpenAI blurb cache path. Unit tests cover the prompt builder + the cache eviction; a "blurb shows up in mobile UI within Xms" test does not exist.
Risks with the current architecture
- Convex lock-in. Switching backends is a multi-month project (database export, function rewrite, subscription model re-implementation, deploy infrastructure). Mitigation:
@app/data-contractkeeps schemas portable. - WorkOS dependency. Tenant lock-in is real but manageable — WorkOS is replaceable with any OIDC provider. Migration would be a few days of auth wiring + a one-time user-migration backfill.
- OpenAI dependency. Single-provider for the blurb. Mitigation: graceful degrade on failure, plus the prompt is portable to Anthropic / Google with re-tuning.
- Scorecard schema drift. Federal Scorecard occasionally renames fields between yearly releases. Mitigation:
lib/collegeShape.tsis the only mapper; rename a field there and the rest of the code is unaffected. The drift detector (lib/drift.ts) flags mismatches at refresh time. - Federal data licensing. Scorecard is U.S. public domain. logo.dev and Serper have their own terms; both are within free / pay-as-you-go limits and attribution is rendered where required.
- App Store + Play Store policy changes. Out of NXT's control. The mobile app today complies; future policy moves (e.g. mandatory IAP for in-app purchases) would require feature changes.
Recommended next priorities
In rough order:
- Turn on Sentry. ~10 minutes (set DSN env vars on Convex + Vercel + EAS). Free tier covers expected volume.
- Configure Convex outbound backups. ~30 minutes. Defense-in-depth against catastrophic deletion.
- Move backend deploy to GitHub Actions. ~1 day. Removes operator-machine dependency.
- Audit the
by_active_score→ aggregate-component cutover. Finish the migration to remove a known-legacy index path. - Decide on Spanish locale. Translation + light QA; no engineering blocker.
- Spike a per-rail discover query split. Measure first. The single-roundtrip query is fine today; the test is whether p99 latency degrades as the user base grows.
- Define a credential rotation policy. No rotation has happened. Calendar it.
None of the above blocks shipping or operating the app today.
Technical detail
What "partial" means here
Partial = "shipping in production, working for users, but a piece of intended scope is missing." Trade-school UI ships and works; trade-specific apprenticeship listings would extend it. The aggregate components run and serve some queries; the legacy index is not yet retired.
Why deferred items are listed at all
So nobody accidentally rebuilds something that was intentionally not built. "Why don't you have chat with counselors?" deserves "we decided against it for X reason" rather than a re-discussion from zero.
Where unfinished work lives
- Open tasks in the project's GitHub Issues (where filed).
// TODO:comments tagged in source with file, not generic..runbooks/for one-off operational backfills that need a fresh pair of hands.
There are no half-finished implementations checked into main. The pre-push gate + lint catches "implementation feels too complex to finish" before it merges.