Official website for the Buenos Aires AI Safety Hub (BAISH) - a community dedicated to AI safety research, education, and community building in Latin America.
This is a complete rebuild of the BAISH website using modern web technologies. The project delivers:
- 100% content parity with the existing site plus a new Research section
- Component-based architecture reducing maintenance burden by 80%
- Bilingual support (Spanish and English) with URL-based routing
- High performance targeting Lighthouse scores of 90+ across all metrics
- Modern tech stack: Astro 5.x, TypeScript 5.9+, Tailwind CSS 4.x
BAISH aims to advance AI safety understanding and research in Latin America through educational programs, community events, and research initiatives. This website serves as the central hub for:
- Educational Resources: Curated learning paths, handbook chapters, recommended readings
- Community Events: Course registrations, discussion groups, paper reading clubs
- Research Showcase: Highlighting BAISH research outputs and publications
- Community Connection: Contact forms, newsletter, Telegram community links
- Node.js 20.x or later
- npm 10.x or later
npm installStart the development server:
npm run devVisit http://localhost:4321 to view the site.
npm run dev- Start development servernpm run build- Build production site todist/npm run preview- Preview production build locally
npm run typecheck- Run TypeScript type checkingnpm run lint- Lint code with ESLintnpm run format- Format code with Prettier
Unit tests use Vitest to test utility functions and business logic.
npm run test:unit- Run unit tests oncenpm run test:watch- Run unit tests in watch modenpm run test:coverage- Generate coverage reportnpm run test:ui- Open interactive Vitest UI
Coverage Target: 90%+ for utility functions (src/utils/)
End-to-end tests use Playwright to test critical user journeys across browsers.
npm run test:e2e- Run E2E tests (headless)npm run test:e2e:ui- Run E2E tests in interactive UI mode (recommended for development)npm run test:e2e:headed- Run E2E tests with visible browsernpm run test:e2e:debug- Run E2E tests in debug modenpm run test:report- View last E2E test report
Browsers: Chrome, Firefox, Safari (desktop + mobile viewports)
For detailed E2E testing patterns and best practices, see playwright/README.md.
npm testRuns both unit tests and E2E tests sequentially.
After running npm run test:coverage, open the HTML coverage report:
open coverage/index.htmlCoverage reports show line, branch, function, and statement coverage for all tested files.
All pushes and pull requests trigger automated quality checks via GitHub Actions. View workflow status in the Actions tab.
Pipeline Steps (.github/workflows/ci.yml):
- Type Checking -
npm run typecheck(TypeScript strict mode validation) - Linting -
npm run lint(ESLint code quality checks) - Unit Tests -
npm run test:coverage(Vitest with 90%+ coverage target) - Coverage Upload - Codecov integration for coverage tracking
- E2E Tests -
npm run test:e2e(Playwright cross-browser tests) - Production Build -
npm run build(Astro SSG build todist/)
Branch Protection: Pull requests cannot be merged unless all CI steps pass. The main branch is protected against force pushes and requires status checks.
The site auto-deploys to Vercel on every commit.
Production Deployment:
- URL: https://baishwebsite.vercel.app
- Trigger: Merges to
mainbranch - Build: Vercel runs
npm run buildand deploysdist/to global edge CDN - Monitoring: Vercel Analytics tracks pageviews and Core Web Vitals
Preview Deployments:
- URL Pattern:
https://baishwebsite-git-{branch}-{user}.vercel.app - Trigger: Every pull request automatically gets a unique preview URL
- Testing: Preview deployments allow testing changes in production-like environment before merge
Deployment Flow:
Developer pushes to PR branch
↓
[GitHub Actions CI] [Vercel Preview Build]
├─ Typecheck ├─ npm run build
├─ Lint └─ Deploy to preview URL
├─ Unit tests
├─ E2E tests
└─ Build
↓
CI PASS → PR Mergeable | CI FAIL → PR Blocked
↓
Merge to main
↓
[Vercel Production Build]
├─ npm run build
└─ Deploy to https://baishwebsite.vercel.app
Vercel provides instant rollback via dashboard:
- Navigate to Vercel Dashboard → Deployments
- Find the previous successful deployment
- Click "..." → "Promote to Production"
- Previous version goes live instantly (no rebuild required)
Alternatively, roll back via Git:
git revert <commit-hash>
git push origin mainVercel will auto-deploy the reverted commit.
For initial configuration:
- Vercel Deployment: docs/setup-vercel-deployment.md
GitHub branch protection is configured via the repository settings on GitHub. See GitHub's documentation for instructions.
Vercel Analytics provides cookieless, GDPR-compliant tracking:
- Metrics: Pageviews, top pages, referrers, devices, browsers
- Performance: Core Web Vitals (LCP, FID, CLS)
- Access: Vercel Dashboard → Analytics tab
No configuration needed - analytics auto-enabled for all deployments.
baish-website/
├── .github/
│ └── workflows/ # CI/CD workflows (GitHub Actions)
│ ├── ci.yml # Main CI pipeline (typecheck, lint, test, build)
│ └── lighthouse.yml # Lighthouse CI for performance monitoring
├── src/
│ ├── components/ # Reusable Astro & Preact components
│ │ ├── layout/ # Layout components (Header, Footer, BaseLayout, MobileNav)
│ │ ├── ui/ # UI components (Button, Card, Hero, LanguageToggle)
│ │ ├── domain/ # Domain-specific components (future: Events, Research)
│ │ └── animations/ # Animation components (future: Hero animation)
│ ├── content/ # Content Collections (Astro content layer)
│ │ ├── config.ts # Zod schemas for content validation
│ │ ├── research/ # Research items (future)
│ │ └── handbook/ # Handbook chapters (future)
│ ├── pages/ # File-based routing
│ │ ├── en/ # English pages (/en/*)
│ │ ├── es/ # Spanish pages (/es/*)
│ │ └── index.astro # Root redirect to default locale
│ ├── layouts/ # Page layouts (future: PageLayout, ArticleLayout)
│ ├── i18n/ # Internationalization
│ │ ├── index.ts # Translation utilities (getT, getTranslations)
│ │ ├── en/ # English translations (common.json, home.json, etc.)
│ │ └── es/ # Spanish translations
│ ├── utils/ # Utility functions
│ ├── styles/ # Global styles
│ │ ├── global.css # Tailwind imports, custom theme tokens
│ │ └── animations.css # CSS animation keyframes
│ └── env.d.ts # TypeScript environment type definitions
├── tests/
│ ├── unit/ # Vitest unit tests (90%+ coverage target)
│ └── e2e/ # Playwright E2E tests (critical user flows)
├── playwright/
│ └── support/ # Test fixtures, helpers, and page objects
├── docs/ # Project documentation
│ ├── prd.md # Product Requirements Document
│ ├── architecture.md # Technical architecture and design decisions
│ ├── tech-spec-epic-1.md # Epic 1 technical specifications
│ ├── stories/ # Individual story documents
│ └── *.md # Setup guides, ADRs, implementation notes
├── public/ # Static assets (images, fonts, favicon)
├── astro.config.mjs # Astro framework configuration
├── tsconfig.json # TypeScript configuration (strict mode, path aliases)
├── vitest.config.ts # Vitest test runner configuration
├── playwright.config.ts # Playwright E2E test configuration
├── eslint.config.js # ESLint 9.x flat config
├── .prettierrc.cjs # Prettier code formatter configuration
├── package.json # Dependencies and npm scripts
└── README.md # This file
src/components/layout/: Core layout components shared across all pages (Header, Footer, BaseLayout)src/components/ui/: Reusable UI components (buttons, cards, form elements)src/pages/[locale]/: File-based routing for bilingual pages (/en/*and/es/*)src/i18n/: Translation files organized by locale and namespacesrc/content/: Markdown/MDX content managed via Astro Content Collectionstests/: Automated tests (unit tests with Vitest, E2E tests with Playwright)docs/: Technical documentation, PRD, architecture, and story documents
- Framework: Astro 5.14
- UI Library: Preact 10 (for interactive islands)
- Styling: Tailwind CSS 4
- Language: TypeScript 5.9
- Unit Testing: Vitest 2
- E2E Testing: Playwright 1.55
The site supports Spanish (es) and English (en) using Astro's built-in i18n routing.
i18n is configured in astro.config.mjs:
i18n: {
defaultLocale: 'es', // Spanish is the default
locales: ['en', 'es'], // Supported locales
routing: {
prefixDefaultLocale: true, // Use /es/ prefix (not just /)
redirectToDefaultLocale: false,
},
}- Spanish:
/es/*(e.g.,/es/,/es/about) - English:
/en/*(e.g.,/en/,/en/about)
Translations are stored in JSON files under src/i18n/{locale}/{namespace}.json:
src/i18n/
├── en/
│ ├── common.json # Shared translations (nav, footer)
│ └── home.json # Page-specific translations
└── es/
├── common.json
└── home.json
- Create or update translation files:
// src/i18n/en/common.json
{
"nav": {
"home": "Home",
"about": "About"
},
"footer": {
"copyright": "© 2025 BAISH. All rights reserved."
}
}// src/i18n/es/common.json
{
"nav": {
"home": "Inicio",
"about": "Acerca"
},
"footer": {
"copyright": "© 2025 BAISH. Todos los derechos reservados."
}
}- Use in Astro components:
---
import { getT } from '@i18n';
const currentLocale = (Astro.currentLocale || 'es') as Locale;
const t = await getT(currentLocale, 'common');
---
<nav>
<a href={`/${currentLocale}/`}>{t('nav.home')}</a>
<a href={`/${currentLocale}/about`}>{t('nav.about')}</a>
</nav>common- Navigation, footer, shared UI elementshome- Homepage contentabout- About page contentactivities- Activities page contentresources- Resources page contentresearch- Research page contentcontact- Contact page content
Translation functions are fully typed:
import { getT, type Locale } from '@i18n';
const t = await getT('en', 'common'); // Type-safe locale and namespace
const homeLabel = t('nav.home'); // Returns: stringIssue: Translation key not found warning in console
- Cause: Missing translation key in JSON file
- Solution: Add the key to the appropriate locale file, or it will fallback to the key string
Issue: Build fails with "Cannot resolve @i18n"
- Cause: Path alias not configured
- Solution: Ensure
astro.config.mjshas Vite alias:'@i18n': '/src/i18n'
Issue: Wrong language displays on page
- Cause:
Astro.currentLocalenot set or incorrect - Solution: Verify page is under
/en/or/es/directory insrc/pages/
- Create page files for both locales:
# Create the English version
touch src/pages/en/new-page.astro
# Create the Spanish version
touch src/pages/es/new-page.astro- Use BaseLayout for consistent structure:
---
// src/pages/en/new-page.astro
import BaseLayout from '@components/layout/BaseLayout.astro';
import { getT } from '@i18n';
const currentLocale = (Astro.currentLocale || 'en') as Locale;
const t = await getT(currentLocale, 'new-page'); // Load translations
---
<BaseLayout title={t('meta.title')} description={t('meta.description')} lang="en">
<div class="container mx-auto px-4 py-12">
<h1 class="text-4xl font-bold mb-6">{t('heading')}</h1>
<p class="text-lg">{t('content')}</p>
</div>
</BaseLayout>- Add translations:
// src/i18n/en/new-page.json
{
"meta": {
"title": "New Page - BAISH",
"description": "Description for SEO"
},
"heading": "New Page Heading",
"content": "Page content here..."
}// src/i18n/es/new-page.json
{
"meta": {
"title": "Nueva Página - BAISH",
"description": "Descripción para SEO"
},
"heading": "Encabezado de Nueva Página",
"content": "Contenido de la página aquí..."
}- Update navigation (if adding to main menu):
Edit src/components/layout/Header.astro and add the new link to both locales.
- Test your page:
npm run dev
# Visit http://localhost:4321/en/new-page
# Visit http://localhost:4321/es/new-page- English pages:
/en/page-name - Spanish pages:
/es/page-name - Root (
/) redirects to/es/(Spanish is the default locale)
The site is tested and fully supported on:
- Chrome (last 2 versions)
- Firefox (last 2 versions)
- Safari (last 2 versions) - macOS and iOS
- Edge (last 2 versions)
Not supported: Internet Explorer 11
Mobile browsers:
- Chrome on Android
- Safari on iOS
Graceful degradation: The site provides a functional experience on older browsers, though some animations or advanced features may be simplified or disabled.
This project maintains high performance standards measured by Lighthouse:
| Metric | Target | Status |
|---|---|---|
| Performance | 90+ | Monitored via Lighthouse CI |
| Accessibility | 100 | Enforced in PR reviews |
| Best Practices | 100 | Enforced in PR reviews |
| SEO | 95+ | Monitored via Lighthouse CI |
- First Contentful Paint (FCP): < 1.8s
- Largest Contentful Paint (LCP): < 2.5s
- Cumulative Layout Shift (CLS): < 0.1
- Time to Interactive (TTI): < 3.5s
Performance is tested on:
- Desktop: Modern multi-core CPUs
- Mobile: Simulated slow 4G throttling (Lighthouse mobile emulation)
Lighthouse CI runs automatically on every PR. View reports in:
- GitHub Actions workflow results
- Vercel deployment comments (preview deployments)
We welcome contributions to improve the BAISH website! Here's how to get started:
- Fork and clone the repository
- Create a feature branch from
main:git checkout -b feature/your-feature-name
- Make your changes following our coding standards
- Run quality checks before committing:
npm run typecheck # TypeScript validation npm run lint # Code quality checks npm run format # Auto-format code npm test # Run all tests
- Commit with a descriptive message:
git commit -m "Add feature: brief description" - Push and create a pull request:
git push origin feature/your-feature-name
- TypeScript: Strict mode enabled - all code must be properly typed
- ESLint: Follow the configured ESLint rules (enforced by pre-commit hooks)
- Prettier: Code is auto-formatted on commit (via Husky + lint-staged)
- Tests: Maintain 90%+ coverage for utility functions
- Accessibility: All components must meet WCAG 2.1 AA standards
All PRs must pass the following checks before merging:
- ✅ TypeScript type checking (
npm run typecheck) - ✅ ESLint code quality checks (
npm run lint) - ✅ Unit tests with 90%+ coverage (
npm run test:coverage) - ✅ E2E tests for critical flows (
npm run test:e2e) - ✅ Production build succeeds (
npm run build) - ✅ Lighthouse CI scores meet targets (automated check)
Husky and lint-staged automatically run on every commit:
- Lints and formats staged files
- Prevents commits with linting errors
- Issues: Check existing GitHub Issues or create a new one
- Questions: Join our Telegram community (placeholder link)
- Documentation: See
docs/for technical architecture and guides
- Website: baishwebsite.vercel.app
- Telegram: Join our community for discussions and updates
- Email: contact@baish.org (check website for current contact info)
- Location: Buenos Aires, Argentina (Universidad de Buenos Aires)
- Technical Questions: Open a GitHub Issue
- Bug Reports: Use the issue tracker with detailed reproduction steps
- Feature Requests: Discuss in issues before starting major work
When reporting bugs, please include:
- Browser and OS version
- Steps to reproduce
- Expected vs actual behavior
- Screenshots or error messages (if applicable)
© 2025 Buenos Aires AI Safety Hub. All rights reserved.
Built with ❤️ by the BAISH community using Astro, TypeScript, and Tailwind CSS.