Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/frontend-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Frontend CI — UltravioletaDAO (uvdweb)
# Gate de calidad ANTES de que Amplify despliegue. Branch protection en main
# debe requerir este workflow (ver docs/PIPELINE_SETUP.md).
#
# Nota brownfield: el build corre con CI=false para fallar solo ante ERRORES de
# compilación (no warnings preexistentes). eslint es informativo al inicio.
# Endurecer (CI=true / --max-warnings=0) cuando los warnings estén limpios.
name: Frontend CI

on:
push:
branches: [develop, main]
pull_request:
branches: [main]

jobs:
quality-gates:
name: Lint, Test & Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install
run: npm ci

# 1. Lint — informativo (no bloquea por warnings heredados)
- name: Lint (informativo)
run: npx eslint src/ --ext .js,.jsx || true
continue-on-error: true

# 2. Unit tests — BLOQUEA. passWithNoTests hasta que haya suite real.
- name: Unit Tests
run: npm test -- --watchAll=false --passWithNoTests
env:
CI: true
REACT_APP_API_URL: http://localhost:3001
REACT_APP_DEBUG_ENABLED: 'false'

# 3. Build — BLOQUEA ante errores de compilación reales.
- name: Build verification
run: npm run build
env:
CI: false
REACT_APP_API_URL: https://api.ultravioletadao.xyz
REACT_APP_DEBUG_ENABLED: 'false'
REACT_APP_STREAM_SUMMARIES_API: https://api.ultravioletadao.xyz

# 4. Health check del artefacto
- name: Verificar build
run: |
test -f build/index.html || { echo "ERROR: falta build/index.html"; exit 1; }
SIZE=$(du -sk build | cut -f1)
echo "Build size: ${SIZE}KB"
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ Tests should focus on:
- **SEO**: Use React Helmet for meta tags and ensure all pages have proper SEO configuration
- **Error Handling**: Implement fallbacks for all external API calls
- **Performance**: Use React.memo for expensive components and implement lazy loading where appropriate
- **Git Commits**: NEVER include "Co-Authored-By: Claude <noreply@anthropic.com>" in commit messages. Always remove Claude as a committer.
- **Git Commits**: Include "Co-Authored-By: Claude <noreply@anthropic.com>" in commits made with Claude's assistance. The human remains the author/committer; Claude is credited as co-author.
- **File Organization**:
- All `.md` documentation files must go in the `/docs/` folder to avoid main directory pollution
- All test files must go in the `/tests/` folder
Expand Down
18 changes: 18 additions & 0 deletions amplify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@ frontend:
baseDirectory: build
files:
- '**/*'
customHeaders:
- pattern: '/'
headers:
- key: 'Link'
value: >-
</.well-known/api-catalog>; rel="api-catalog",
</.well-known/mcp/server-card.json>; rel="mcp-server-card",
</.well-known/agent-skills/index.json>; rel="agent-skills",
</.well-known/oauth-protected-resource>; rel="oauth-protected-resource",
</agent-discovery>; rel="service-doc"
- pattern: '/**'
headers:
- key: 'Link'
value: '</.well-known/api-catalog>; rel="api-catalog"'
- pattern: '/.well-known/api-catalog'
headers:
- key: 'Content-Type'
value: 'application/linkset+json'



88 changes: 88 additions & 0 deletions infra/AGENTIC_FASE4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Fase 4 — CloudFront Function: Markdown for Agents

Pasos para adjuntar `cloudfront-markdown-negotiation.js` a la distribución de Amplify.

## Prerequisitos

- AWS CLI configurado con permisos `cloudfront:*` en us-east-1
- `index.md` ya desplegado en Amplify (Fase 1 completada)

## Paso 1 — Obtener el Distribution ID de Amplify

```bash
# Opción A: via CLI de Amplify
aws amplify list-apps --region us-east-1 --query 'apps[].{name:name,appId:appId}'

# Opción B: buscar en CloudFront por dominio de origen
aws cloudfront list-distributions \
--query "DistributionList.Items[?contains(to_string(Origins.Items[0].DomainName), 'amplifyapp')].{Id:Id,Domain:DomainName}" \
--output table
```

Guardar el `Distribution ID` (formato: `EXXXXXXXXXX`).

## Paso 2 — Crear la CloudFront Function

```bash
# Crear la función en us-east-1 (requerido para CloudFront Functions)
aws cloudfront create-function \
--name "uvdao-markdown-negotiation" \
--function-config "Comment=Rewrite to index.md for Accept:text/markdown,Runtime=cloudfront-js-2.0" \
--function-code fileb://infra/cloudfront-markdown-negotiation.js \
--region us-east-1

# Guardar el FunctionARN del output (formato: arn:aws:cloudfront::ACCOUNT:function/uvdao-markdown-negotiation)
```

## Paso 3 — Publicar la función (pasarla de DEVELOPMENT a LIVE)

```bash
# Obtener el ETag de la función recién creada
ETAG=$(aws cloudfront describe-function \
--name uvdao-markdown-negotiation \
--region us-east-1 \
--query 'ETag' --output text)

# Publicar
aws cloudfront publish-function \
--name uvdao-markdown-negotiation \
--if-match "$ETAG" \
--region us-east-1
```

## Paso 4 — Adjuntar al Distribution en viewer-request

Hay que modificar el Default Cache Behavior del distribution para agregar la función.

Amplify gestiona su distribución de CloudFront internamente. La forma más segura es hacerlo via la consola AWS, no via CLI, para evitar conflictos con el estado gestionado por Amplify.

### Via consola AWS (recomendado)

1. Ir a CloudFront → Distributions → `[Distribution ID de Paso 1]`
2. Tab "Behaviors" → seleccionar el Default (`/*`) → Edit
3. Bajar a "Function associations"
4. En "Viewer request" seleccionar: Function type = **CloudFront Functions**, Function ARN = `arn:aws:cloudfront::ACCOUNT:function/uvdao-markdown-negotiation`
5. Save changes
6. Esperar a que el estado pase de "Deploying" a "Deployed" (~2-3 minutos)

## Paso 5 — Verificar

```bash
# Debe retornar Content-Type: text/markdown y contenido markdown
curl -sI -H "Accept: text/markdown" https://ultravioletadao.xyz/ | grep -i content-type
curl -s -H "Accept: text/markdown" https://ultravioletadao.xyz/ | head -5
```

Resultado esperado:
```
Content-Type: text/markdown
# UltravioletaDAO
```

## Notas

- Si Amplify hace un nuevo deploy, CloudFront puede resetear el cache behavior a sus defaults.
Verificar después de cada deploy que la función sigue asociada.
- Alternativa sin CloudFront: agregar ruta `GET /index.md` en `api.ultravioletadao.xyz` que
retorne el contenido con `Content-Type: text/markdown`. Más mantenible pero requiere
Lambda update.
20 changes: 20 additions & 0 deletions infra/cloudfront-markdown-negotiation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// cloudfront-markdown-negotiation.js
// CloudFront Function — Viewer Request event
// Reescribe la request a /index.md cuando el cliente envía Accept: text/markdown
// Adjuntar a la distribución de Amplify en el evento viewer-request del behavior '/*'
//
// Runtime: cloudfront-js-2.0
// Región: us-east-1 (CloudFront Functions siempre en us-east-1)

function handler(event) {
var request = event.request;
var headers = request.headers;
var accept = headers['accept'] ? headers['accept'].value : '';

// Solo para la homepage (raíz) — evitar reescribir assets y rutas SPA
if (request.uri === '/' && accept.includes('text/markdown')) {
request.uri = '/index.md';
}

return request;
}
Loading
Loading