Folder Structure
A guided map of the web/ directory — what lives where, and why.
Every chapter in this handbook refers to folders inside web/ (the web application’s home at the repository root). This page is the map: the whole tree at a glance, then a short tour of each area. The organizing idea is simple — app/ is what the app shows and serves (every folder there is a URL), and everything else is what the app is built from (components, modules, shared logic) or how it is built and checked (configuration, tests, scripts).
The tree at a glance
web/
├── app/ ← the routes: every folder here becomes a URL
│ ├── (public)/ landing page, login, signup
│ ├── (authenticated)/ the product: workspaces, datasets, settings …
│ ├── api/ ← the app's own backend: 97 route handlers
│ ├── api-docs/ the interactive Swagger page
│ ├── auth/ login callbacks, email confirm, password reset
│ └── layout.tsx root layout — wraps every page in the providers
├── middleware.ts ← runs before every request: session refresh,
│ workspace redirects
├── components/ ← reusable UI building blocks (see Component Library)
├── modules/ ← self-contained feature modules (gallery,
│ photo-map-3d, gas-heatmap, thermal-pair-viewer,
│ cad-viewer, dataset-onboarding)
├── lib/ ← shared non-UI logic: Supabase clients, AG-UI,
│ cloud storage, workspace registry, JWT …
├── hooks/ ← shared React behavior (17 use-* hooks)
├── providers/ ← global context providers: session, organization,
│ theme
├── public/ ← files served as-is: icons, manifest, service
│ worker, the Swagger spec (api-docs/swagger.yaml)
├── styles/ ← global CSS and the design-system tokens
├── tests/ ← Vitest suites (api, components, integration) and
│ Playwright end-to-end specs
├── playwright/ ← Playwright's working directory
├── scripts/ ← maintenance scripts: Supabase type generation,
│ Cesium asset copy, test runners
├── types/ ← extra TypeScript declarations
├── assets/ templates/ stories/ ← demo CAD file, design wireframes,
│ component stories
└── package.json, next.config.js, tailwind.config.js, tsconfig.json,
components.json, vitest*.config.ts, playwright.config.ts,
Dockerfile, apphosting.yaml ← build, test & deploy config
app/ — the routes
KAP uses Next.js’s App Router, whose core convention is: the folder tree is the URL structure. A folder app/datasets/[slug]/ with a page.tsx inside renders at /datasets/<some-dataset>; square brackets mark the variable parts. Three special ideas explain the rest:
- Route groups — folder names in parentheses, like
(public)and(authenticated), organize routes without appearing in the URL. Their job here is to give the two halves of the app different wrappers: pages in(public)/(landing, login, signup) get the marketing chrome, while pages in(authenticated)/get the signed-in app shell. Inside(authenticated)/live the product surfaces:w/— the workspaces (/w/data-explorer,/w/integrity, covered in Workspaces) — plus datasets, organizations, settings, profile, insights, anomalies, and the CAD viewer. app/api/— the backend. Folders here define API route handlers instead of pages: code the browser calls for data rather than screens a person visits. This is the 97-handler backend documented in Backend API & Swagger;app/api-docs/is the page that renders its Swagger documentation.layout.tsxfiles wrap everything below them. The rootapp/layout.tsxwraps every page in the global providers (session, organization, theme — fromproviders/); each route group adds its own layout on top.
A few top-level entries (app/dashboard/, app/datasets/create/, app/auth/…, app/onboarding/) predate the route groups and live directly under app/ — same conventions, just outside the two groups.
The complete list of the URLs this tree produces — every page route, in plain English — is the Page Route Inventory.
Alongside app/ sits middleware.ts — not a route, but the code that runs before every request: it refreshes the caller’s Supabase session and redirects users to the right workspace (see the architecture diagram).
components/, modules/ — what screens are built from
components/holds the reusable UI building blocks, from the ~50 generic primitives incomponents/ui/up through the workspace shell and feature components. It has its own chapter with the full tree and inventory.modules/holds the six self-contained feature modules — gallery, photo-map-3d, gas-heatmap, thermal-pair-viewer, cad-viewer, and dataset-onboarding. Each is a mini-application with its own internalcore/,ui/,shared/,services/, andoverlays/folders and a single public entry point (index.ts); the heavy 3D/viewer surfaces live here. How modules plug into workspaces is the subject of Workspace Modules.
public/, styles/ — served as-is, and the look
public/is served verbatim at the site root: icons and logos, the PWAmanifest.jsonand service workersw.js, map markers — andapi-docs/swagger.yaml, which is why the raw spec has a stable URL.styles/holdsglobals.cssand thedesign-system/tokens;tailwind.config.jsat the root turns those tokens into the utility classes components use.
tests/, playwright/, scripts/ — checking and upkeep
tests/is organized by kind:api/(route-handler tests),components/,integration/, ande2e/(Playwright browser specs), with sharedmocks/and setup files. The Vitest configs at the root (vitest.config.ts,vitest.components.config.ts) andplaywright.config.tswire them up.scripts/holds maintenance tooling — regenerating Supabase types (generate-supabase-types.mjs), copying Cesium’s static assets, test runners, and deploy helpers (apphosting/).
The root config files
| File | What it controls |
|---|---|
package.json |
Dependencies and the npm run commands (dev, build, test) |
next.config.js |
Next.js build behavior |
tsconfig.json |
TypeScript rules and the @/… import alias |
tailwind.config.js |
The design tokens available as utility classes |
components.json |
Where the shadcn/ui generator puts new primitives |
middleware.ts |
The every-request gatekeeper (see above) |
Dockerfile, apphosting.yaml |
How the app is containerized and deployed |
Last Updated: 2026-07-30