mirror of
https://github.com/fosrl/pangolin.git
synced 2026-11-10 01:32:29 -06:00
135 lines
8.1 KiB
Markdown
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"`.
|