Architecture overview
Evaluate the Gravity monorepo structure, service boundaries, tooling, and current implementation gaps across web, API, and AI services.
Overview
Gravity is currently a polyglot monorepo scaffold with three independently runnable applications under apps/: a Remix frontend at apps/web, a NestJS API at apps/api, and a FastAPI service at apps/ai-service. The repository already has workspace orchestration, per-service Dockerfiles, semantic version files, and GitHub Actions pipelines, but the application layer is still intentionally thin.
The practical architecture today is best understood as a deployment-ready foundation rather than a feature-complete platform. Each service starts, builds, and ships independently, but there are no shared packages, no persistence layer, no authentication system, and no implemented cross-service request flow beyond the API allowing browser requests from http://localhost:3000.
pnpm-workspace.yaml includes packages/*, and the README describes planned shared packages, but no packages/ directory exists in the current repository tree.
Top-level repository structure
The repository root contains the orchestration, build, and operational layers that tie the three applications together.
.github/.github/workflows/web.yml.github/workflows/api.yml.github/workflows/ai-service.yml
apps/apps/webapps/apiapps/ai-service
scripts/scripts/bootstrap.shscripts/version-bump.sh
README.mdpackage.jsonpnpm-lock.yamlpnpm-workspace.yamltsconfig.base.jsonturbo.json
A few root files define the monorepo shape directly:
pnpm-workspace.yamlregistersapps/*andpackages/*as workspaces.turbo.jsonconfigures a minimal task graph fordevandbuild.package.jsondefines root development commands that delegate into the app workspaces.scripts/bootstrap.shinstalls toolchains and service dependencies across JavaScript, Bun, and Python environments.
Monorepo orchestration layer
The repo uses pnpm workspaces for package coordination and Turborepo primarily as a process orchestrator. At the current maturity level, Turborepo is not modeling a deep dependency graph because there are no shared internal packages yet.
The root package.json defines workspace-level commands such as dev:web, dev:api, and dev. Those commands establish the intended local development pattern: run services independently when needed, or run them in parallel through Turbo.
The root script dev:py points to apps/py-service, but the actual Python service lives at apps/ai-service. That script is stale relative to the repository tree.
Service architecture
apps/web: Remix frontend
apps/web is the user-facing frontend. It uses Remix with Vite and React, and the current code remains close to a starter application rather than an integrated product UI.
The main entry file is apps/web/app/root.tsx. That file defines the document shell, global styles, font links, an ErrorBoundary, and the route outlet. The exported app component returns an Outlet, so request handling follows standard Remix nested routing.
Current route files are minimal:
apps/web/app/routes/_index.tsxapps/web/app/routes/home.tsx
Both routes render the same component from apps/web/app/welcome/welcome.tsx. There are no route loaders, no route actions, no session handling, no data fetching helpers, and no API client layer in the current frontend tree.
apps/web/vite.config.ts shows the active frontend stack:
- Remix
- Vite
- Tailwind CSS
- TypeScript path support
The relationship to the rest of the repo is mostly implicit. The API service enables CORS for http://localhost:3000, which indicates the frontend is expected to call the API, but no such calls are implemented in the frontend code today.
apps/api: NestJS API on Bun
apps/api is the TypeScript backend boundary. It uses NestJS for the HTTP framework, Bun as the runtime for local development and execution, and TypeScript compilation to dist/ for builds.
The service boots from apps/api/src/main.ts. That file creates the Nest application, enables CORS for http://localhost:3000, and listens on port 3001.
The root module lives at apps/api/src/app.module.ts. Its composition is currently minimal: one root module and one controller, with no providers, feature modules, guards, pipes, interceptors, or middleware classes registered.
The only implemented controller is apps/api/src/health/health.controller.ts. It exposes GET /health and returns a static payload indicating the API is healthy. There is no service layer, DTO layer, repository layer, or domain module structure behind that endpoint.
That makes apps/api a real runnable service, but architecturally it is still a shell. The service boundary exists at the application level, not yet at the module or domain level.
apps/ai-service: FastAPI Python service
apps/ai-service is the Python service intended to host AI-related functionality. In its current state, it is a very small FastAPI application with one route and no internal substructure.
The entry point is apps/ai-service/main.py. That file creates a FastAPI app and defines GET /health, which returns a static status object. There are no routers, service classes, Pydantic models beyond what FastAPI would support, middleware, persistence adapters, or model-inference integrations implemented yet.
The Python project configuration lives in apps/ai-service/pyproject.toml. Dependencies include fastapi, pydantic, and uvicorn, with ruff and pytest declared for development. The tooling is ready for a larger service, but the runtime surface area is currently limited to health checking.
Despite the service name ai-service, the current codebase does not include integrations with model providers, vector databases, inference libraries, or any AI-specific application logic.
Entry points and request handling
Each application has a clear entry point, but request handling remains shallow.
Web routes
The frontend entry point is apps/web/app/root.tsx, with route modules under apps/web/app/routes/.
Current route behavior:
/is defined byapps/web/app/routes/_index.tsx/homeis defined byapps/web/app/routes/home.tsx
Both route modules render the same welcome component. There are no loaders, actions, or backend requests in those routes.
API routes
The API entry point is apps/api/src/main.ts, and the only route controller is apps/api/src/health/health.controller.ts.
Implemented route behavior today:
GET http://localhost:3001/health
The repository README reportedly references /api/health, but apps/api/src/main.ts does not set a global prefix. Based on the code, the implemented route is /health, not /api/health.
AI service routes
The AI service entry point is apps/ai-service/main.py.
Implemented route behavior today:
GET /health
There are no additional routers or path groupings.
Module relationships and service boundaries
The repository has strong top-level separation and very thin internal layering. The clearest boundaries today are folder boundaries:
apps/webfor the frontendapps/apifor the TypeScript backendapps/ai-servicefor the Python backend
Inside those boundaries, the internal module graph is still mostly absent. The Nest app does not yet follow a controller-to-service-to-repository pattern. The FastAPI app does not yet split routes into routers or separate business logic into services. The frontend does not yet separate route modules from API clients, domain packages, or shared contracts.
That means the current architecture is macro-separated but not yet layered. The repo signals where responsibilities will likely live, but those responsibilities are not implemented in code yet.
Current cross-service wiring
Expected relationships are visible in naming and configuration, not in running integrations.
apps/api/src/main.tsallows CORS fromhttp://localhost:3000, implying browser calls from the web app.- The repository README describes a future shared-contract pattern through planned packages.
- The presence of both
apps/apiandapps/ai-serviceimplies a future backend-to-backend relationship.
No direct wiring exists today:
- no frontend fetches to the API in
apps/web - no API client or SDK package
- no API calls from
apps/apitoapps/ai-service - no shared
packages/code - no shared schema or contract definitions
Treat the current topology as three isolated services managed in one monorepo, not as an already integrated multi-service system.
Persistence, middleware, auth, and external services
Database and persistence
No database or persistence layer is implemented in the current repository. There are no ORM configurations, migration files, schema directories, repository classes, entity models, or connection settings that would indicate active persistence.
Notably absent from the tree:
prisma/db/ordatabase/- ORM setup for TypeORM, Prisma, Drizzle, MikroORM, Mongoose, or Sequelize
- SQL migration files
- Redis or cache clients
.env.examplewith database connection variables
The practical result is a stateless system. The frontend renders starter UI, the API returns a hardcoded health response, and the AI service returns a hardcoded health response.
Middleware
Middleware is also minimal across all services.
- In
apps/api/src/main.ts, the only visible platform-level request configuration is CORS. - In
apps/web, there is no evidence of session middleware, CSRF protection, cookie handling, or request interception. - In
apps/ai-service/main.py, there is no middleware configured.
This absence matters architecturally because cross-cutting concerns have not yet been formalized. Logging, validation, auth enforcement, and request context propagation are still future concerns.
Authentication and authorization
No authentication or authorization layer exists today.
There are no signs of:
- login or logout endpoints
- JWT or session cookies
- Passport or strategy modules in Nest
- Remix session storage
- user identity models
- authorization guards or policy enforcement
The absence is consistent across all three applications. Any future protected routes, user-specific state, or service-to-service trust model will need to be added from scratch.
External services and integrations
Actual external integrations are limited.
Present today:
- browser-to-API CORS allowance for
http://localhost:3000inapps/api/src/main.ts - Google Fonts references in
apps/web/app/root.tsx - GitHub Container Registry publishing in
.github/workflows/web.yml,.github/workflows/api.yml, and.github/workflows/ai-service.yml
Not present today:
- model provider APIs
- databases
- caches
- queues
- cloud object storage
- email or SMS providers
- payment providers
- OAuth providers
- observability or APM tooling
- feature flag systems
Build, release, and deployment tooling
The operational layer is more mature than the application layer. Each app has enough tooling to build, version, containerize, and publish independently.
Local setup
scripts/bootstrap.sh checks for pnpm, bun, and uv, then installs dependencies for the JavaScript and Python services. That script reflects the repo's polyglot design: each app uses the native tooling expected for its runtime.
Versioning
Each app has a local VERSION file:
apps/web/VERSIONapps/api/VERSIONapps/ai-service/VERSION
scripts/version-bump.sh updates those version files, establishing per-service version management rather than one monorepo-wide application version.
Containers and CI/CD
Each service has its own Dockerfile:
apps/web/Dockerfileapps/api/Dockerfileapps/ai-service/Dockerfile
Each service also has its own GitHub Actions workflow:
.github/workflows/web.yml.github/workflows/api.yml.github/workflows/ai-service.yml
Those workflows handle build and verification steps, version generation, Docker image publishing to GitHub Container Registry, and GitHub release creation. The deployment sections are present as placeholders, which means release automation is implemented further than environment deployment.
Notable gaps and inconsistencies
A few repo details can mislead an architectural review unless they are called out directly.
Shared packages are planned but absent
pnpm-workspace.yaml includes packages/*, and the README describes shared packages for types, UI, and config. The actual file tree does not contain a packages/ directory.
That gap matters because the intended contract-sharing architecture does not exist yet in code. No current module should be assumed to share types or UI primitives through a workspace package.
Script and naming drift around the Python service
The repository uses apps/ai-service as the actual Python service path, but some root-level references still point to py-service. The most concrete example is the root package.json script that targets apps/py-service.
This inconsistency affects local development expectations and is a sign that repo documentation and scripts have not fully caught up with the current directory structure.
API route documentation mismatch
The README references /api/health, but the implemented Nest app does not set a global prefix in apps/api/src/main.ts. The existing controller path in apps/api/src/health/health.controller.ts therefore resolves to /health.
When evaluating the system, trust the source files over the README for current route shape.
Testing exists mostly as intent
The Python service declares pytest, and the workflows reference verification steps, but the repository does not yet show a meaningful test suite. The CI layer is prepared for broader testing, while the codebase itself remains at an early implementation stage.
The strongest part of the current architecture is operational structure: app boundaries, runtime separation, containerization, and release automation. The weakest part is application depth: no domain modules, no persistence, no auth, and no implemented service-to-service flows.
What this architecture means today
Gravity already answers some important architectural questions. It has chosen service boundaries, runtimes, build tools, and release mechanics. That gives the repository a stable foundation for future feature work.
What it has not answered yet are the application-level questions: where domain logic lives, how contracts are shared, how state is stored, how users authenticate, and how the API and AI service collaborate. Until those layers exist, the repo should be evaluated as a well-structured platform skeleton rather than as an implemented distributed system.
Related pages
Introduction
Get the high-level orientation for the documentation set and how the project is presented.
Quickstart
Follow the shortest path to running the project and validating the local setup.
Features
Review the documented capabilities and compare them with the current implementation state.
Help center
Find troubleshooting and support-oriented guidance for common setup and usage issues.