The backend for Orbit -- an AI-powered habit tracker. Provides a REST API for habit management, an AI agent (chat + MCP tools), gamification, goals, calendar sync, social/accountability, push notifications, and subscription billing. Built with Clean Architecture and CQRS.
Live: api.useorbit.org | App: app.useorbit.org | Landing: useorbit.org
| Layer | Technology |
|---|---|
| Runtime | .NET 10.0, C# 13 |
| Database | PostgreSQL via EF Core 10 (Npgsql) |
| CQRS | MediatR 14 |
| Validation | FluentValidation 12 |
| Auth | JWT Bearer + email verification codes + Google OAuth (Supabase tokens) |
| AI | OpenAI — gpt-4.1-mini (primary), gpt-5.4-nano (sub-tasks), via the OpenAI .NET SDK |
| Resend (verification codes, contacts) | |
| Push | Firebase Admin SDK (FCM, native Android) + WebPush (VAPID, browsers) |
| Payments | Stripe (web) + Google Play Billing (native Android) |
| Storage | Supabase object storage (uploads bucket) |
| Password/Token Hashing | BCrypt |
| Observability | Sentry |
| API Docs | Scalar (dev only) |
| Testing | xUnit + FluentAssertions |
| Containerization | Docker (multi-stage build) |
- Habit CRUD -- Create, update, delete, duplicate, reorder habits with sub-habit support
- Smart Scheduling -- Server-side frequency calculations (daily, weekly, monthly, yearly, every N days) with day-of-week filtering and overdue detection
- Completion Logging -- Toggle completion per day with optional notes, full log history
- Metrics -- Current/longest streaks, weekly/monthly completion rates
- AI Agent -- Multi-turn OpenAI-backed chat that creates habits, logs completions, analyzes progress, suggests breakdowns, assigns tags, and reschedules. Exposed to external clients as MCP tools with per-tool ownership/policy scoping and audit logging. Supports image upload
- AI Assists -- Cached daily summaries, retrospectives, fact extraction, goal review, habit/tag/reschedule suggestions, proactive check-ins, slip alerts, and batched usage summaries
- Gamification -- XP, levels, streaks, streak freezes, and achievements
- Goals -- Goal tracking with deadlines and AI-assisted review
- Calendar -- Google Calendar auto-sync of scheduled habits
- Social & Accountability -- Friends, public profiles, accountability partners, challenges, and referrals
- Checklist Templates -- Reusable habit/checklist templates
- Tags -- Colored tags for habit organization
- User Facts -- Personal context facts that enhance AI responses (soft-deleted)
- Push Notifications -- Dual delivery: FCM for native Android, VAPID Web Push for browsers, plus background schedulers for reminders, goal deadlines, slip alerts, and check-ins
- Email Verification -- Passwordless code-based login via Resend
- Subscription Billing -- Stripe (web) and Google Play Billing (native) with webhook / RTDN processing; backend is the source of truth for entitlements
- Waitlist -- Signed-token waitlist confirmation flow
- Sync -- Batched pull/mutation sync endpoints for clients
- Timezone Support -- All user-facing dates use timezone-aware "today" based on user profile
- Pagination -- List endpoints paginated with
PaginatedResponse<T>
- .NET 10.0 SDK
- PostgreSQL (or Supabase for hosted)
- Docker (optional, for containerized deployment)
# Clone the repository
git clone https://github.com/thomasluizon/orbit-api.git
cd orbit-api
# Copy environment config
cp .env.example .env
# Edit .env / appsettings.Development.json with your database credentials and API keys
# Apply database migrations
dotnet ef database update --project src/Orbit.Infrastructure --startup-project src/Orbit.Api
# Run the API
dotnet run --project src/Orbit.ApiThe API runs at http://localhost:5000. API docs available at /scalar in development.
Settings are bound from appsettings.json, with secrets overridden in appsettings.Development.json locally and environment variables in production. Key sections:
| Section | Purpose |
|---|---|
ConnectionStrings:DefaultConnection / SessionConnection |
PostgreSQL (direct + session pooler) |
AI:ApiKey / AI:Model / AI:SubTaskModel / AI:BaseUrl |
OpenAI credentials and models (BaseUrl defaults to https://api.openai.com/v1) |
Jwt:SecretKey / Issuer / Audience |
JWT signing and claims |
Supabase:Url / AnonKey / SecretKey / Bucket |
Supabase auth tokens + object storage |
Resend:ApiKey / FromEmail |
Transactional email |
Vapid:PublicKey / PrivateKey / Subject |
Web Push (VAPID) |
Encryption:Key |
At-rest field encryption |
Google:ClientId / ClientSecret |
Google OAuth + Calendar |
Stripe:SecretKey / WebhookSecret / price IDs |
Stripe billing |
Cors:AllowedOrigins / LandingOrigins |
Allowed frontend origins |
Sentry:Dsn / Environment |
Error monitoring |
Clean Architecture with four layers:
src/
Orbit.Api/ # Presentation layer
Controllers/ # 26 controllers (see below)
Extensions/ # PayGate-aware IActionResult helpers
Middleware/ # Security headers, unhandled/validation exception handlers
Program.cs # DI configuration, middleware pipeline
Orbit.Application/ # Application layer (CQRS)
Common/ # PaginatedResponse<T>, ErrorMessages, AppConstants, PayGateService, ...
Habits/ # Commands / Queries / Validators / Services (HabitScheduleService)
Chat/ # AI chat orchestration
Goals/ Gamification/ # Goals, XP/streaks/achievements
Calendar/ # Google Calendar sync
Accountability/ Social/ Challenges/ Referrals/ # Social graph
ChecklistTemplates/ Tags/ UserFacts/ Uploads/ # Content
Auth/ Profile/ ApiKeys/ Subscriptions/ Support/ Notifications/ Waitlist/
Behaviors/ # MediatR pipeline (ValidationBehavior, ...)
Orbit.Domain/ # Domain layer (zero dependencies)
Entities/ Enums/ Interfaces/ Common/ Models/ # Entities, Result<T>, repository/service contracts
Orbit.Infrastructure/ # Infrastructure layer
Persistence/ # OrbitDbContext, GenericRepository<T>, UnitOfWork
Services/ # AI (AiIntentService, AiSummaryService, OpenAiBatchPollerService, ...),
# Agent/MCP (AgentCatalogService, AgentOperationExecutor, AgentPolicyEvaluator, ...),
# billing (StripeBillingService, GooglePlayBillingService),
# push + schedulers (PushNotificationService, ReminderSchedulerService, ...),
# auth (JwtTokenService, GoogleTokenService), UserDateService, EncryptionService
Migrations/ # EF Core migrations
tests/
Orbit.Domain.Tests/ # xUnit + FluentAssertions
Orbit.Application.Tests/ # xUnit + FluentAssertions
Orbit.Infrastructure.Tests/ # xUnit + FluentAssertions
Accountability, Achievements, Ai, ApiKeys, Auth, Calendar, Challenges, Chat, ChecklistTemplates, Config, Friends, Gamification, Goals, Habits, Notification, OAuth, Profile, PublicProfile, Referral, Subscription, Support, Sync, Tags, Uploads, UserFacts, Waitlist.
- Result<T> -- Handlers return
Result<T>instead of throwing for expected failures - CQRS -- Command/query separation via MediatR, one folder per feature
- Factory methods -- Entities created via
Entity.Create()static methods - Generic repository + Unit of Work -- Abstracted data access
- PayGate -- Subscription-gated features via
PayGateServiceandResultpropagation helpers - Validation pipeline --
ValidationBehavior<TRequest, TResponse>in the MediatR pipeline - Cache invalidation -- AI summary cache cleared on any habit mutation
Dual delivery via PushNotificationService:
- FCM -- Firebase Admin SDK for native Android. Subscriptions with
p256dh == "fcm"route through Firebase - Web Push -- VAPID-based for browsers, via
Lib.Net.Http.WebPush - Schedulers -- Background services (
ReminderSchedulerService,GoalDeadlineNotificationService,SlipAlertSchedulerService,ProactiveCheckinSchedulerService) send push + create in-app notifications; aSentReminderrecord prevents duplicates
# Run all unit tests
dotnet testTests use xUnit with FluentAssertions. Unit tests only — there is no integration or E2E suite.
| Component | Service |
|---|---|
| Hosting | Render (Docker, auto-deploy on push to main) |
| Database | Supabase PostgreSQL (session pooler) |
| Domain | api.useorbit.org |
| Push | Firebase project orbit-11d4a (FCM) |
| Resend | |
| Payments | Stripe + Google Play Billing |
| Monitoring | Sentry |
# Build and run with Docker Compose
docker compose up -d --buildThe Dockerfile uses a multi-stage build (SDK for build, ASP.NET runtime for production) and runs as a non-root user.
| Repo | Description |
|---|---|
| orbit-ui-mobile | Turborepo frontend — apps/web (Next.js 16) + apps/mobile (Expo, Android) + packages/shared |
| orbit-landing-page | Marketing landing page |
Private project.