# Arizona Institute for Autism Astro Site Static Astro + TypeScript migration of the public Arizona Institute for Autism website. ## Quick Start Run commands from this directory: ```sh cd www npm install npm run dev ``` Astro prints the local development URL, normally: ```txt http://localhost:4321 ``` The development server watches source files and refreshes the browser after edits. Stop it with `Ctrl+C`. ## Environment Setup Requirements: - Node.js 20.19 or newer; the Nix shell currently supplies Node.js 22 - npm This repository also has a Nix development shell at the repository root: ```sh cd .. nix --extra-experimental-features "nix-command flakes" develop cd www npm install ``` Copy the example environment file when testing the like/view counter or staging SEO behavior: ```sh cp .env.example .env ``` The default values are: ```txt PUBLIC_AIA_API_BASE=https://api.azinstitute4autism.com PUBLIC_ALLOW_INDEXING=false ``` The site still renders when the AIA API is unavailable. Migration and staging builds emit `noindex,nofollow` by default. `PUBLIC_ALLOW_INDEXING=true` enables production publication policy, including per-page noindex exceptions. Exercise that mode locally with `PUBLIC_ALLOW_INDEXING=true npm run build`; this does not deploy anything or change environment files. Run `npm run build` afterward to restore staging output. Only explicitly authorized production deployments should publish indexing-enabled artifacts. ## View And Build ### Development Server Use this while editing: ```sh npm run dev ``` Useful development URLs include: ```txt / /aba-therapy /autism-evaluations /learner-social-club /client-consultation /library /es /es/library /ar/library ``` ### Static Build Generate the static site with staging indexing protection: ```sh npm run build ``` The autonomous Codex sandbox denies `/etc/hosts`, so its Node runtime cannot resolve `localhost`. Use this equivalent validation command only inside that sandbox: ```sh npm run build:sandbox ``` Build output is written to: ```txt dist/ ``` ### Preview Production Output After a successful build: ```sh npm run preview ``` Astro prints the preview URL, normally `http://localhost:4321`. ### Validate Before Committing ```sh npm run build npm run audit:links npm run audit:images npm run audit:blog ``` The link audit reads `dist/` after a successful build. If rendered output is unavailable, it audits generated source routes, relative and root-relative Markdown links, and public assets instead. It writes: ```txt reports/broken-links.md ``` ## Editing Content Normal content editing happens in Markdown: ```txt src/content/pages/en src/content/pages/es src/content/pages/ar src/content/blog/en src/content/blog/es src/content/blog/ar src/content/authors/en src/content/authors/es src/content/authors/ar ``` Page and post frontmatter is validated by `src/content.config.ts`. Example: ```md --- title: "Example Article" description: "Short search and social description." slug: "example-article" canonical: "https://www.azinstitute4autism.com/library/example-article" lang: "en" translationKey: "example-article" featuredImage: "/assets/images/example.webp" alt: "Descriptive image alt text" date: "2026-06-07" author: "rula-diab" category: "Library" tags: - ABA Therapy draft: false --- Article content goes here. ``` Set `draft: true` while preparing unpublished content. ### Publication, Canonicals, and Sitemap `src/utils/publication-policy.ts` owns route eligibility, normalized public URLs, canonical validation, robots values, and sitemap eligibility. `src/utils/publication.ts` loads the Astro collections into that manifest. `src/pages/[...slug].astro` generates every content route from eligible entries, including home and Library indexes; their existing presentation components are under `src/components/pages/`. Shared SEO and the generated sitemap use that same manifest. The route and source-link audits also reuse the policy. - `draft: true` means unpublished: no generated HTML route in either build mode. The Arabic homepage `/ar` remains a draft; published Arabic Library routes remain available. Navigation does not link to the unpublished homepage. - `noindex: true` keeps a published route accessible, emits `noindex,follow` in indexing-enabled builds, and excludes it from the sitemap. It defaults to `false`. Staging always overrides this with `noindex,nofollow`. - An omitted `canonical` gets the normalized public URL from `site.json` and its local route. A supplied local canonical must match that route. Invalid canonicals, duplicate canonical targets, and route collisions fail validation. - Verified syndicated articles use their existing `canonical` field for the external publisher URL. External-canonical routes are excluded from the sitemap even when they are not marked noindex. Do not use canonical values to create local routes or sitemap locations. - `src/pages/sitemap.xml.ts` generates `dist/sitemap.xml` on every build. Staging emits an empty sitemap and does not advertise it in `robots.txt`. Indexing-enabled builds include only eligible, indexable, self-canonical local routes. There is no hand-maintained `public/sitemap.xml`. - `npm run generate:sitemap` is a compatibility command that runs the Astro build; it no longer writes a separate public sitemap from frontmatter strings. The verified noindex exceptions are `/schedule-consultation`, `/employee-portal`, `/library/community-highlight-meet-rula-diab`, and `/library/new-aia-scottsdale-office`. The last two also retain their verified external canonicals. The dated evidence is in `reports/migration-summary.md`. Run `npm run test:publication` for policy tests and isolated builds of the actual application in staging and indexing-enabled modes. Fixtures test draft content, draft home/Library indexes, missing and external canonicals, and generated head/sitemap consistency without modifying the working site's output. The policy is TypeScript; Node audit/test commands use `--experimental-strip-types` for compatibility with the declared Node 22.12 minimum. Dependencies are unchanged. After publication changes, build and run `npm run audit:routes -- --offline` before `npm run audit:routes -- --check`. This creates a newly dated local reconciliation using saved production observations, preserving earlier evidence. Saved rendered metadata is specific to its build mode: after restoring the normal staging build, reconcile that output again before checking it. ### Links And Buttons Use normal Markdown links for links within prose: ```md Read the [ABA therapy guide](/aba-therapy) for more information. ``` Prose links render as the live site's orange inline links. Do not place an ordinary Markdown link on its own line merely to make it look like a button. Use `.mdx` and the `Button` component only for a source-verified call to action: ```mdx import Button from '../../../components/Button.astro'; ``` Available `Button` variants are `filled` (default), `outlined`, and `light`. Available sizes are `default` and `small`. A `_blank` target automatically adds `rel="noopener noreferrer"`. Normal Markdown links remain preferred for ordinary page and article content. ### Stable Heading Links Astro automatically generates an ID for each Markdown heading. In `.md` files, when a section needs a stable, editorially controlled fragment link, add an explicit ID with Sätteri heading-attribute syntax: ```md ## Accepted Insurance Carriers {#accepted-insurance-heading} ``` Link to it with the resulting fragment URL: ```md [View accepted carriers](/insurance#accepted-insurance-heading) ``` Keep explicit IDs unique within the page, lowercase, and hyphenated. Treat a published ID as permanent so inbound links do not break when heading text is edited. The installed MDX parser rejects this shorthand, independently of directive parsing. In `.mdx` files, use an explicit HTML heading instead: ```mdx