8.1 KiB
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()), withinternalfrom@app/lib/apiandauthCookieHeaderfrom@app/lib/api/cookies. UsegetCachedOrg/getCachedOrgUserfrom@app/lib/api/*for the org. - Client components:
const api = createApiClient(useEnvContext());, thenapi.get/put/post/delete. Errors go totoast({ variant: "destructive", description: formatAxiosError(e, t("...")) }). - Response types are imported straight from the server router, e.g.
import { GetResourceResponse } from "@server/routers/resource".