Files
2026-11-09 16:23:48 -05:00

135 lines
8.1 KiB
Markdown

# Repo map
A quick map of where things live, so you can go straight to the right file.
Path aliases (from `tsconfig*.json`):
| Alias | Resolves to | Use from |
| --- | --- | --- |
| `@server/*` | `server/*` | anywhere (server and UI, for shared types) |
| `@app/*`, `@/*` | `src/*` | UI |
| `@test/*`, `@cli/*` | `test/*`, `cli/*` | tests, CLI |
| `#private/*` | `server/private/*` | **only** inside `server/private/` |
| `#dynamic/*` | `server/private/*` (enterprise/saas) or `server/*` (oss) | outside `server/private/` when you need the private implementation on paid builds |
| `#open/*`, `#closed/*` | `server/*`, `server/private/*` | internal to the esbuild `#dynamic` switcher; don't use |
## Top level
```
server/ Express API server (TypeScript, bundled with esbuild.mjs)
src/ Next.js dashboard (App Router)
messages/ i18n JSON. Only en-US.json is edited by hand; Crowdin generates the others
config/ config.yml (+ privateConfig.yml on enterprise), example configs
cli/ pangctl CLI
install/ installer (Go)
docs/ Developer docs for agents and contributors (this folder)
test/ Shared test helpers
scripts/ Build/test scripts (run-tests.mjs)
esbuild.mjs Server bundler; holds the #private guard and the #dynamic switcher
drizzle.*.ts Drizzle configs (drizzle.config.ts is generated by set:pg / set:sqlite)
```
Generated and gitignored, switched by npm scripts: `server/build.ts`
(`npm run set:oss|enterprise|saas`), `tsconfig.json` (copied from
`tsconfig.{oss,enterprise,saas}.json`), `server/db/index.ts`, `drizzle.config.ts`,
`server/setup/migrations.ts` (`npm run set:sqlite|pg`).
## server/
```
server/
index.ts Entry. Boots config, migrations, and all servers below
apiServer.ts External API (dashboard + user API). Routes: #dynamic/routers/external
internalServer.ts Internal API (Next server-side fetches, badger). Routes: #dynamic/routers/internal
integrationApiServer.ts Integration API (API keys, OpenAPI docs). Routes: #dynamic/routers/integration
aiGatewayServer.ts AI gateway
nextServer.ts Serves the Next app
openApi.ts OpenAPITags enum + registry
build.ts GENERATED: `build` = "oss" | "enterprise" | "saas"
auth/ actions.ts (ActionsEnum), sessions/, password, totp, canUserAccess*.ts
middlewares/ verify*Access.ts, verifyUserHasAction, verifyLimits, logActionAudit (stub)
integration/ verifyApiKey*.ts counterparts for the integration API
routers/ One folder per entity (see below) + router files:
external.ts Dashboard/user routes (session auth)
internal.ts Internal routes
integration.ts API-key routes (needs public-/private-resource aliases)
hybrid.ts Hybrid/remote node routes
private/ ENTERPRISE/SAAS ONLY (see docs/enterprise-private-code.md)
routers/{external,internal,integration,hybrid}.ts Import the public routers and add private routes
routers/<entity>/ Private-only handlers
lib/ Private implementations of #dynamic modules, config, redis, stripe, billing
lib/readConfigFile.ts privateConfigSchema (private config values)
lib/config.ts `privateConfig` singleton
middlewares/ Real logActionAudit etc.
lib/
config.ts `config` singleton: config.getRawConfig()
readConfigFile.ts Public config zod schema
crypto.ts encrypt/decrypt (AES, keyed by server.secret)
blueprints/ Blueprint schema (types.ts) + apply (publicResources.ts, privateResources.ts) + export
traefik/ Traefik dynamic config generation for public resources
billing/tierMatrix.ts TierFeature -> tiers; used by server and UI paywalls
response.ts `response()` envelope helper
validators.ts, schemas.ts Shared zod validators
deleteResource.ts, deleteSiteResource.ts, deleteOrg.ts Cascading delete helpers
rebuildClientAssociations.ts Recomputes client <-> site resource access
db/
index.ts GENERATED: re-exports ./pg or ./sqlite + `driver`
pg/schema/{schema,privateSchema}.ts Postgres tables
sqlite/schema/{schema,privateSchema}.ts SQLite tables (must mirror pg)
setup/ Startup tasks + migrations (scriptsPg/, scriptsSqlite/). Don't edit unless asked
emails/ React email templates
routers/newt/ Messages to/from Newt (site connector) over websockets
routers/olm/ Messages to/from Olm (client connector)
routers/gerbil/ Exit node (WireGuard) coordination
routers/badger/ Traefik auth plugin endpoints (verifySession)
routers/traefik/ Traefik HTTP config provider
routers/ws/ Websocket server (private/routers/ws for enterprise)
```
### Entity routers (`server/routers/<entity>/`)
Each folder has `index.ts` (re-exports), one file per operation
(`createX.ts`, `getX.ts`, `listXs.ts`, `updateX.ts`, `deleteX.ts`), and often
`types.ts` / `validation.ts`. See `docs/crud-endpoints.md`.
Main ones: `org`, `site`, `resource` (public resources), `siteResource` (private
resources), `target` (public resource targets), `policy` (resource policies),
`client`, `user`, `role`, `domain`, `idp`, `apiKeys`, `accessToken`,
`blueprints`, `labels`, `redirect`, `aiProvider`, `aiBudget`, `virtualApiKey`,
`auditLogs`, `certificates`.
## src/ (dashboard)
```
src/
app/
layout.tsx, navigation.tsx Root layout; sidebar nav items (orgNavSections etc.)
[orgId]/settings/ All org settings pages (one folder per section)
layout.tsx Sidebar shell
general/ Org settings: layout.tsx (tabs) + page.tsx, security/, logs/, auth-page/
resources/public/ Public resources: page.tsx (list), create/, [niceId]/<tab>/
resources/private/ Private (site) resources: page.tsx, create/, [niceId]/<tab>/
sites/, clients/, access/, domains/, api-keys/, blueprints/, ai-providers/, ...
(private)/ Route group for enterprise-only pages (billing, idp, license, policies, remote-exit-nodes)
admin/ Server admin pages
auth/ Login, signup, 2FA, resource auth pages
components/
ui/ shadcn primitives (button, form, input, select, tabs, ...)
Credenza.tsx Responsive modal (dialog on desktop, drawer on mobile). Use for every modal
DismissableBanner.tsx Help/info banner (wrapped by *Banner.tsx components)
HorizontalTabs.tsx Route-based tabs used in [id]/layout.tsx files
Settings.tsx SettingsContainer / SettingsSection / ... layout primitives
SettingsSectionTitle.tsx Page title + description
PaidFeaturesAlert.tsx Paywall notice for tiered features
ConfirmDeleteDialog.tsx Type-the-name-to-delete Credenza
contexts/ + providers/ + hooks/ Context per entity: OrgProvider/useOrgContext,
ResourceProvider/useResourceContext,
SiteResourceProvider/useSiteResourceContext, useEnvContext, usePaidStatus, ...
lib/
api/ index.ts: createApiClient (client), `internal` (server components), formatAxiosError; cookies.ts: authCookieHeader
pullEnv.ts Builds the Env object (flags etc.) from process.env for the UI
```
### Fetching data
- **Server components / layouts**: `internal.get<AxiosResponse<T>>(path, await authCookieHeader())`, with `internal` from `@app/lib/api` and `authCookieHeader` from `@app/lib/api/cookies`. Use `getCachedOrg` / `getCachedOrgUser` from `@app/lib/api/*` for the org.
- **Client components**: `const api = createApiClient(useEnvContext());`, then `api.get/put/post/delete`. Errors go to `toast({ variant: "destructive", description: formatAxiosError(e, t("...")) })`.
- Response types are imported straight from the server router, e.g. `import { GetResourceResponse } from "@server/routers/resource"`.