Workspace Files
The root package.json, pnpm-workspace.yaml, and Justfile define the common entry points. Prefer those commands when a change crosses package boundaries.
pnpm install
just lint
just test
just buildDocs Settings
The docs app lives in docs/. Astro configuration is in docs/astro.config.mjs, while shell and prose styles are colocated in docs/src/layouts/DocLayout.astro and component styles stay with the component that owns the markup.
Documentation pages are MDX files under docs/src/content/docs/. The left sidebar and search index scan those files automatically from their frontmatter.
Web And Docs Trackers
The web app and docs site can load optional browser trackers at build time. Use the VITE_NETSTAMP_* prefix for web/ and the PUBLIC_NETSTAMP_* prefix for docs/.
| Suffix | Purpose | Default |
|---|---|---|
GA_MEASUREMENT_ID | Google Analytics GA4 measurement ID | empty |
GOOGLE_TAG_ID | Generic Google tag ID, used before GA_MEASUREMENT_ID | empty |
CLARITY_PROJECT_ID | Microsoft Clarity project ID | empty |
POSTHOG_KEY | PostHog project API key | empty |
POSTHOG_HOST | PostHog API host | https://us.i.posthog.com |
PLAUSIBLE_DOMAIN | Plausible site domain | empty |
PLAUSIBLE_SCRIPT_URL | Plausible script URL for cloud or self-hosted deployments | https://plausible.io/js/script.js |
UMAMI_WEBSITE_ID | Umami website ID | empty |
UMAMI_SCRIPT_URL | Umami script URL for cloud or self-hosted deployments | https://cloud.umami.is/script.js |
TRACKING_CONSENT_MODE | regional, always, or never consent gating | regional |
TRACKING_CONSENT_COUNTRIES | Comma-separated ISO country codes that require consent | EEA, UK, and Switzerland |
When any tracker ID is set, regional mode asks for consent only in configured countries. If the visitor country cannot be resolved, the banner is shown before trackers load. Country resolution checks window.NETSTAMP_VISITOR_COUNTRY, <html data-netstamp-country>, <meta name="netstamp-visitor-country">, then Cloudflare /cdn-cgi/trace.
Demo Access Controls
Self-hosted demo deployments can reuse real data while blocking writes. These backend settings are enforced at runtime:
| Variable | Purpose | Default |
|---|---|---|
DEMO_MODE | Blocks unsafe API methods except login and logout | false |
AUTH_REGISTRATION_ENABLED | Allows POST /auth/register when demo mode is not enabled | true |
Set DEMO_MODE=true for a public demo instance. AUTH_REGISTRATION_ENABLED=false is still useful for clarity, but demo mode blocks registration and all other unsafe API requests before they reach feature handlers. Keep a separate normal deployment pointed at the same database if operators still need full access.
The observability Docker Compose file starts a locked demo controller and static web bundle against the same PostgreSQL database and observability services:
docker compose -f deployments/docker/compose.observability.yaml up -d --buildThe web app has matching build-time flags that hide the disabled UI controls:
| Variable | Purpose | Default |
|---|---|---|
VITE_NETSTAMP_REGISTRATION_ENABLED | Shows registration routes and links | true |
VITE_NETSTAMP_PROJECT_CREATION_ENABLED | Shows project creation controls | true |
VITE_NETSTAMP_USER_CREDENTIAL_CHANGES_ENABLED | Shows email and password forms | true |
VITE_NETSTAMP_DEMO_MODE | Shows demo-mode read-only UI | false |
VITE_NETSTAMP_DEMO_EMAIL | Shows a demo login email | empty |
VITE_NETSTAMP_DEMO_PASSWORD | Shows a demo login password | empty |
When VITE_NETSTAMP_DEMO_MODE=true and both demo credential values are set, the login page shows the account and a button that fills the login form. Demo mode is explicit; disabling registration alone does not enable the demo banner. The backend runtime settings are the source of truth. The Vite flags only control the static frontend bundle built for that deployment.
Observability Host
The observability compose stack serves Grafana on its own host.
| Variable | Purpose | Default |
|---|---|---|
BACKEND_BASE_URL | Public controller origin for generated URLs | https://app.netstamp.dev |
GRAFANA_DOMAIN | Grafana public domain | grafana.netstamp.dev |
GRAFANA_ROOT_URL | Grafana public root URL | https://grafana.netstamp.dev/ |
Backend And API Assets
Backend source lives in server/. The docs API explorer reads docs/public/openapi.json, which should be regenerated from the TypeSpec contract when API behavior changes. Non-production backend environments also expose Scalar docs at /api/v1/docs; production does not register that runtime docs route or /api/v1/openapi.json.
Database Image
Docker Compose uses TIMESCALEDB_IMAGE for the PostgreSQL/TimescaleDB service and defaults it to the lightweight timescale/timescaledb:latest-pg16 image.
Current migrations enable core TimescaleDB only. Result series downsampling uses time_bucket, so TimescaleDB Toolkit and DB-side lttb are not required. If a future schema adds extra extensions, the selected image must include those extension packages before Goose can enable them.
Shared UI
Reusable React primitives live in packages/ui/ and are consumed by both the service app and docs. Static documentation for those components is published through the Storybook build at /storybook/.
Update Rules
When configuration changes affect local commands, project structure, or documentation behavior, update the closest AGENTS.md guide in the same change.