Skip to content

Commit 490740f

Browse files
author
non-stop-dev
committed
feat: add CI workflow, contributing guidelines, security policy, and style files for enhanced project structure and documentation
1 parent 2d98ccb commit 490740f

9 files changed

Lines changed: 700 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
validate:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Checkout repository
13+
uses: actions/checkout@v4
14+
15+
- name: Setup Node.js
16+
uses: actions/setup-node@v4
17+
with:
18+
node-version: 22
19+
cache: pnpm
20+
21+
- name: Enable pnpm via Corepack
22+
run: corepack enable pnpm
23+
24+
- name: Install dependencies
25+
run: pnpm install --frozen-lockfile
26+
27+
- name: Run project checks
28+
run: pnpm check

CONTRIBUTING.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Contribuir a CV Optimizer
2+
3+
Gracias por querer contribuir.
4+
5+
## Antes de abrir un PR
6+
7+
- Usa `Node.js 22.12.0` o superior.
8+
- Usa `pnpm`.
9+
- Crea tu `.env` a partir de `.env.example` si necesitas probar integración con IA.
10+
- No subas secretos, API keys ni archivos `.env`.
11+
12+
## Configuración local
13+
14+
```sh
15+
corepack enable pnpm
16+
pnpm install
17+
cp .env.example .env
18+
pnpm dev
19+
```
20+
21+
## Checklist mínimo
22+
23+
Antes de abrir un PR, ejecuta:
24+
25+
```sh
26+
pnpm check
27+
```
28+
29+
Eso corre:
30+
31+
- typecheck
32+
- tests
33+
- build
34+
35+
## Reglas del proyecto
36+
37+
- Mantén los archivos por debajo de `500` líneas.
38+
- Si tocas una feature folder, actualiza su `README.md` cuando cambie la estructura o el flujo.
39+
- Mantén el HTML semántico y la sanitización como fuente única de verdad.
40+
- No introduzcas dependencias nuevas si no son realmente necesarias.
41+
- No rompas la separación entre contenido generado y estilos de plantilla.
42+
43+
## Pull requests
44+
45+
- Describe claramente qué cambia y por qué.
46+
- Si corriges un bug, añade o actualiza tests.
47+
- Si cambias documentación o setup, verifica que el README siga siendo suficiente para alguien que no conoce el proyecto.

SECURITY.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Security Policy
2+
3+
## Alcance
4+
5+
Este proyecto procesa documentos de usuario y se integra con proveedores externos de IA, así que los reportes de seguridad son relevantes sobre todo en estas áreas:
6+
7+
- sanitización de archivos subidos
8+
- manejo de HTML generado
9+
- almacenamiento local en el navegador
10+
- integración con proveedores de IA
11+
- exposición accidental de secretos o credenciales
12+
13+
## Cómo reportar un problema
14+
15+
- No publiques secretos, API keys, tokens ni payloads sensibles en issues públicos.
16+
- Si GitHub Private Vulnerability Reporting está disponible en el repo, úsalo.
17+
- Si no está disponible, abre un issue público solo con una descripción mínima del problema y sin detalles sensibles, indicando que se trata de un problema de seguridad.
18+
19+
## Buenas prácticas para contribuidores
20+
21+
- Nunca subas `.env`, claves reales o documentos privados.
22+
- Redacta cualquier CV de ejemplo antes de compartirlo.
23+
- Mantén la sanitización y las validaciones activas cuando cambies el flujo de upload o exportación.
24+
25+
## Versiones soportadas
26+
27+
Por ahora, la rama principal (`main`) es la única versión soportada.

public/cv-optimizer-preview.mp4

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:9e1d58a0c957a9d30ad2c98cbe87577d3b14d84cb285fb053538f03767d91b08
3-
size 244970962
2+
oid sha256:105699c7f1ab1754a8ba760663f7e7fbe3272757521ba8a6cc0b74f2058cfb94
3+
size 95961776

src/server/export-cv/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Export CV
2+
3+
Este feature concentra la salida final del CV editado y la personalización visual usada durante la exportación.
4+
5+
## Contenido
6+
7+
- `cv-export.ts`: construye el HTML exportable, genera el TXT limpio, normaliza nombres de archivo y abre la vista de impresión.
8+
- `cv-preview-color.ts`: aplica el color primario del preview editable sin tocar la estructura del contenido.
9+
10+
## Entry Points
11+
12+
- [`cv-export.ts`](./cv-export.ts)
13+
- [`cv-preview-color.ts`](./cv-preview-color.ts)
14+
15+
## Data Flow
16+
17+
```mermaid
18+
flowchart LR
19+
A["Editor HTML"] --> B["sanitizeCvHtml"]
20+
B --> C["buildHtmlExportDocument / buildPrintableHtml"]
21+
C --> D["download HTML / print preview"]
22+
A --> E["downloadTextFile"]
23+
F["Primary color + template id"] --> C
24+
F --> G["createPreviewColorApplicator"]
25+
```
26+
27+
## Constraints
28+
29+
- La exportación debe mantener HTML semántico y seguro.
30+
- El TXT exportado debe seguir siendo plain text sin markdown ni estilos.
31+
- El flujo PDF actual depende de la impresión del navegador; cualquier exportador automático futuro debe preservar la misma plantilla visual.

src/server/text-editor/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Text Editor
2+
3+
Este feature concentra las utilidades de edición enriquecida que actúan sobre la selección activa dentro del CV editable.
4+
5+
## Contenido
6+
7+
- `active-selection-formatting.client.ts`: aplica y revierte formato inline seguro sobre selecciones válidas dentro del editor.
8+
- `active-selection-formatting.client.test.ts`: cubre selección, restauración, formato inline y enlaces permitidos.
9+
10+
## Entry Points
11+
12+
- [`active-selection-formatting.client.ts`](./active-selection-formatting.client.ts)
13+
14+
## Data Flow
15+
16+
```mermaid
17+
flowchart LR
18+
A["Toolbar click"] --> B["captureSelectionRange"]
19+
B --> C["applyInlineTextFormat / applyLinkOnSelection"]
20+
C --> D["Updated contenteditable DOM"]
21+
```
22+
23+
## Constraints
24+
25+
- El formato solo debe aplicarse dentro del editor activo.
26+
- Los enlaces inseguros (`javascript:`, `data:`, `vbscript:`) deben rechazarse.
27+
- La restauración de la selección no debe romper el flujo del toolbar del optimizador.

src/styles/global-brutal-ui.css

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
.brutal-paper {
2+
position: relative;
3+
overflow: hidden;
4+
border: 2px solid var(--line);
5+
background: linear-gradient(180deg, rgba(255, 255, 255, 0.96) 0%, var(--paper) 100%);
6+
box-shadow: 10px 10px 0 var(--shadow);
7+
}
8+
9+
.brutal-paper::before {
10+
content: "";
11+
position: absolute;
12+
inset: 0;
13+
background:
14+
linear-gradient(
15+
90deg,
16+
transparent 0 2.25rem,
17+
rgba(255, 90, 54, 0.18) 2.25rem 2.35rem,
18+
transparent 2.35rem
19+
),
20+
repeating-linear-gradient(
21+
180deg,
22+
transparent 0 1.9rem,
23+
var(--paper-rule) 1.9rem 1.96rem
24+
);
25+
opacity: 0.78;
26+
pointer-events: none;
27+
}
28+
29+
.brutal-chip {
30+
display: inline-flex;
31+
align-items: center;
32+
justify-content: center;
33+
border: 2px solid var(--line);
34+
background: var(--note-yellow);
35+
box-shadow: 4px 4px 0 var(--shadow);
36+
font-family: 'Sora', 'Avenir Next', 'Segoe UI', sans-serif;
37+
font-size: 0.74rem;
38+
font-weight: 800;
39+
letter-spacing: 0.22em;
40+
text-transform: uppercase;
41+
}
42+
43+
.brutal-note {
44+
position: relative;
45+
border: 2px solid var(--line);
46+
box-shadow: 8px 8px 0 rgba(18, 18, 18, 0.95);
47+
}
48+
49+
.brutal-note::before {
50+
content: "";
51+
position: absolute;
52+
top: -0.75rem;
53+
left: 1rem;
54+
width: 4rem;
55+
height: 1.1rem;
56+
border: 2px solid var(--line);
57+
background: rgba(255, 255, 255, 0.62);
58+
transform: rotate(-7deg);
59+
}
60+
61+
.brutal-panel {
62+
position: relative;
63+
overflow: hidden;
64+
border: 2px solid var(--line);
65+
background: linear-gradient(180deg, rgba(255, 255, 255, 0.96) 0%, var(--paper) 100%);
66+
box-shadow: 10px 10px 0 var(--shadow);
67+
}
68+
69+
.brutal-card {
70+
border: 2px solid var(--line);
71+
background: rgba(255, 255, 255, 0.96);
72+
box-shadow: 6px 6px 0 rgba(18, 18, 18, 0.94);
73+
}
74+
75+
.brutal-control {
76+
display: inline-flex;
77+
align-items: center;
78+
justify-content: center;
79+
gap: 0.65rem;
80+
border: 2px solid var(--line);
81+
background: #ffffff;
82+
box-shadow: 4px 4px 0 rgba(18, 18, 18, 0.94);
83+
transition:
84+
transform 180ms ease,
85+
box-shadow 180ms ease,
86+
background-color 180ms ease,
87+
color 180ms ease;
88+
}
89+
90+
.brutal-control:hover,
91+
.brutal-control:focus-visible {
92+
transform: translate(-2px, -2px);
93+
box-shadow: 7px 7px 0 rgba(18, 18, 18, 0.94);
94+
}
95+
96+
.brutal-control:focus-visible {
97+
outline: 3px solid rgba(0, 163, 122, 0.32);
98+
outline-offset: 3px;
99+
}
100+
101+
.brutal-field {
102+
width: 100%;
103+
border: 2px solid var(--line);
104+
background: #ffffff;
105+
box-shadow: 4px 4px 0 rgba(18, 18, 18, 0.88);
106+
color: var(--ink-strong);
107+
}
108+
109+
.brutal-field:focus-visible {
110+
outline: 3px solid rgba(0, 163, 122, 0.32);
111+
outline-offset: 3px;
112+
}
113+
114+
.brutal-tooltip {
115+
border: 2px solid var(--line);
116+
background: #fffdf8;
117+
box-shadow: 6px 6px 0 rgba(18, 18, 18, 0.94);
118+
}
119+
120+
.brutal-warning {
121+
position: relative;
122+
overflow: hidden;
123+
padding: 1.45rem 1rem 1rem 1rem;
124+
border: 3px solid var(--line);
125+
background:
126+
linear-gradient(180deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0) 48%),
127+
linear-gradient(135deg, #ff7a4f 0%, #ff5a36 52%, #ff8d5a 100%);
128+
box-shadow: 10px 10px 0 rgba(18, 18, 18, 0.96);
129+
color: #fffdf8;
130+
transform: rotate(-4deg);
131+
}
132+
133+
.brutal-warning::before {
134+
content: "";
135+
position: absolute;
136+
inset: 0 0 auto 0;
137+
height: 0.75rem;
138+
border-bottom: 3px solid var(--line);
139+
background: repeating-linear-gradient(
140+
135deg,
141+
var(--line) 0 0.85rem,
142+
var(--note-yellow) 0.85rem 1.7rem
143+
);
144+
}
145+
146+
.warning-icon {
147+
display: inline-flex;
148+
height: 2.4rem;
149+
width: 2.4rem;
150+
flex-shrink: 0;
151+
align-items: center;
152+
justify-content: center;
153+
border: 3px solid var(--line);
154+
background: var(--paper);
155+
box-shadow: 4px 4px 0 rgba(18, 18, 18, 0.92);
156+
color: var(--accent-red);
157+
}
158+
159+
.brutal-button {
160+
display: inline-flex;
161+
align-items: center;
162+
justify-content: center;
163+
gap: 0.65rem;
164+
padding: 0.9rem 1.35rem;
165+
border: 2px solid var(--line);
166+
background: #ffffff;
167+
box-shadow: 6px 6px 0 var(--shadow);
168+
font-family: 'Sora', 'Avenir Next', 'Segoe UI', sans-serif;
169+
font-size: 0.95rem;
170+
font-weight: 800;
171+
letter-spacing: 0.02em;
172+
color: var(--ink-strong);
173+
text-decoration: none;
174+
transition:
175+
transform 180ms ease,
176+
box-shadow 180ms ease,
177+
background-color 180ms ease,
178+
color 180ms ease;
179+
}
180+
181+
.brutal-button:hover,
182+
.brutal-button:focus-visible {
183+
transform: translate(-2px, -2px);
184+
box-shadow: 9px 9px 0 var(--shadow);
185+
}
186+
187+
.brutal-button:focus-visible {
188+
outline: 3px solid rgba(0, 163, 122, 0.35);
189+
outline-offset: 3px;
190+
}
191+
192+
.brutal-button--accent {
193+
background: var(--accent-red);
194+
color: #ffffff;
195+
}
196+
197+
.brutal-button--mint {
198+
background: var(--note-mint);
199+
}

0 commit comments

Comments
 (0)