AgentSkillsCN

frontend-architecture

前端架构采用 Astro SSG(预构建静态页面)与 Jinja2 SSR(服务器端渲染页面)相结合的方式。对于小型片段更新(如卡片大小或更小的组件),可使用 HTMX;而对于复杂的有状态组件(如 SignalChainBuilder),则采用 React Island 技术。GTS 特定的模式。

SKILL.md
--- frontmatter
name: frontend-architecture
description: Frontend architecture with Astro SSG (pre-built static pages) and Jinja2 SSR (server-rendered pages). HTMX for small fragment updates (card-sized or smaller). One build system, two rendering strategies.
context: fork

Frontend Architecture

Activation: architecture, frontend routing, nginx, astro, jinja, when to use

CRITICAL: Pre-Bundled Architecture

Astro is pre-bundled. astro/dist/ is committed to git. No Vite dev server at runtime.

  • nginx serves static files directly from bind-mounted astro/dist/
  • Runtime containers: db, backend, nginx
  • Astro container only used for builds (just build-astro)

CRITICAL: Two rendering strategies, NOT two frontends.

Astro is the build system for all templates. Static pages are served by nginx, dynamic pages are rendered by FastAPI/Jinja2. Both use the same design tokens and CSS.

Architecture Overview

code
                           ┌─────────────────────────────────────────┐
                           │                 Nginx                    │
                           │  Port 80/443 (production) or 9000 (dev)  │
                           └──────────────────┬──────────────────────┘
                                              │
                    ┌─────────────────────────┼─────────────────────────┐
                    │                         │                         │
                    ▼                         ▼                         ▼
         ┌──────────────────┐      ┌──────────────────┐      ┌──────────────────┐
         │   Static Files   │      │   FastAPI/Jinja2 │      │     API Routes   │
         │  (Astro SSG)     │      │   (Dynamic)      │      │   /api/v1/*      │
         └──────────────────┘      └──────────────────┘      └──────────────────┘
                    │                         │                         │
                    │                         │                         │
         /, /about, /login        /shootouts, /library/*         REST + HTML
         /404, /500, /jobs        /shootout/*                   Fragments

Route Ownership

Static Pages (Astro SSG via Nginx)

RoutePurpose
/Home page
/aboutAbout page
/loginOAuth login initiation
/404Not found error page
/500Server error page
/report-errorError reporting form
/report-error/thanksError report confirmation
/jobsBackground jobs status
/dev/showcase/*Component showcase (dev only)

Characteristics:

  • Pre-built at deploy time
  • Served directly by nginx (fastest)
  • No runtime server needed
  • Uses Tailwind CSS

Dynamic Pages (Jinja2/HTMX via FastAPI)

RoutePurpose
/shootoutsPublic shootout discovery
/gear/{slug}Public pack detail page
/library/my-gearUser's saved gear
/library/shootoutsUser's shootouts
/library/chainsUser's signal chains
/library/chains/buildSignal chain builder (React island)
/library/di-tracksUser's DI tracks
/shootout/{id}Shootout detail view
/shootout/createShootout creation wizard

Characteristics:

  • Server-rendered on each request
  • Authentication-aware
  • Uses HTMX for interactivity
  • Uses Alpine.js for UI state

Unified Design Tokens

Design tokens (CSS variables, Tailwind config) are defined ONCE in the Astro source and shared with Jinja2 templates via a build-time wrapper.

Architecture

code
astro/src/styles/global.css (design tokens - single source of truth)
    ↓ Astro build (just build-astro)
astro/dist/layouts/base.html (Jinja2-compatible wrapper with CSS link)
astro/dist/_astro/*.css (compiled Tailwind with all design tokens)
    ↓ Committed to git, bind-mounted into containers
FastAPI loads templates from astro/dist (all templates pre-built by Astro)
    ↓
Dynamic pages extend the Astro-built wrapper

Note: astro/dist/ is committed to git. Commit both source and dist after changes.

How It Works

  1. Design tokens defined once: astro/src/styles/global.css contains all CSS custom properties
  2. Astro builds a Jinja2 wrapper: astro/src/pages/layouts/base.html.astro outputs a Jinja2-compatible template
  3. Compiled CSS included: The wrapper links to the Astro-built CSS with all design tokens
  4. FastAPI loads templates: All Jinja2 templates are served from astro/dist
  5. Jinja2 templates extend the wrapper: Dynamic pages use {% extends "layouts/base.html" %} to get consistent styling

Adding Design Tokens

To add or modify design tokens:

  1. Edit astro/src/styles/global.css
  2. Run just build-astro (or use just watch-astro for auto-rebuild)
  3. Both static and dynamic pages automatically use the updated tokens
  4. No backend restart needed - Jinja2 templates auto-reload from disk

Shared Dependencies

Both rendering strategies load these libraries (via the unified wrapper):

LibraryVersionPurpose
HTMX2.0.4Server-driven DOM updates
Alpine.js3.14.8Lightweight reactivity
Tailwind CSSBuiltUtility-first styling

Template Inheritance

Astro pages: Use Layout.astro component Jinja2 pages: Extend layouts/base.html (from Astro build output)

React Islands

React is used ONLY for SignalChainBuilder at /library/chains/build.

Why React here:

  • Complex drag-drop interactions
  • React DnD library requirements
  • State management complexity

Loading pattern:

html
<!-- In Jinja2 template -->
{% block scripts %}
<script src="/static/islands/signal-chain-builder.js"></script>
<script>
  window.SignalChainBuilder.mount('signal-chain-builder');
</script>
{% endblock %}

React is NOT loaded on any other page. Verify with browser DevTools if unsure.

Decision Guide: Which Rendering Strategy?

RequirementUse This
No authentication neededStatic (Astro SSG)
Content rarely changesStatic (Astro SSG)
SEO critical, no user dataStatic (Astro SSG)
User-specific contentDynamic (Jinja2/HTMX)
Authentication requiredDynamic (Jinja2/HTMX)
Real-time data neededDynamic (Jinja2/HTMX)
Complex interactivity (drag-drop)React island

Nginx Routing Configuration

nginx
# Static pages - served directly
location = / { try_files /index.html @backend; }
location = /about { try_files /about/index.html @backend; }
location = /login { try_files /login/index.html @backend; }

# Dynamic pages - proxy to FastAPI
location /shootouts { proxy_pass http://backend:8000; }
location /gear { proxy_pass http://backend:8000; }
location /library { proxy_pass http://backend:8000; }
location /shootout { proxy_pass http://backend:8000; }

# API routes
location /api { proxy_pass http://backend:8000; }

Common Misconceptions

"We should have only one rendering strategy"

WRONG. Each strategy serves its purpose:

  • Static pages are faster (pre-built, nginx-served)
  • Dynamic pages handle authentication and user-specific data
  • Using both is intentional and optimal

"HTMX is only for Jinja2 pages"

WRONG. HTMX can be used in Astro pages too. The home page uses HTMX for loading featured shootouts.

"React is forbidden"

WRONG. React is used for SignalChainBuilder. The guidance is "React only where needed" not "never use React."

File Locations

ComponentLocation
Design tokensastro/src/styles/global.css
Astro pagesastro/src/pages/
Astro layoutastro/src/layouts/Layout.astro
Jinja2 wrapper sourceastro/src/pages/layouts/base.html.astro
Jinja2 wrapper (built)astro/dist/layouts/base.html (committed to git)
Jinja2 pagesastro/dist/pages/ (built from astro/src/pages/pages/)
HTMX fragmentsastro/dist/fragments/ (built from astro/src/pages/fragments/)
React islandastro/src/islands/
Compiled CSSastro/dist/_astro/*.css (committed to git)
Static pages (built)astro/dist/*.html (committed to git)

Quality Verification

When modifying templates:

bash
# Build Astro (auto-reloads in backend)
just build-astro

# Watch mode (run in separate terminal) - auto-rebuilds on file changes
just watch-astro

# Astro checks
docker compose --profile build exec astro pnpm lint
docker compose --profile build exec astro pnpm check

# Backend checks (templates served by FastAPI)
docker compose exec backend mypy app/
docker compose exec backend pytest /tests/integration/backend/ -k page

# Full check
just check

Related Skills

  • gts-frontend-dev - Jinja2/HTMX development patterns
  • htmx - HTMX-specific patterns
  • testing - Playwright tests for both rendering strategies