diagram-db 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ # Changelog
2
+
3
+ Formato basado en [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/).
4
+ El proyecto usa [versionado semántico](https://semver.org/lang/es/).
5
+
6
+ ## [0.2.0] — 2026-10-29
7
+
8
+ Primera versión distribuible como paquete de Python.
9
+
10
+ ### Añadido
11
+
12
+ - Paquete instalable con `pip install diagram-db` y el comando `diagram-db`.
13
+ - Landing pública en <https://jeironpro.github.io/diagram-db/> con un
14
+ playground que ejecuta el analizador real en el navegador.
15
+ - `import graphviz` deja de ser obligatorio: sin el paquete se pueden exportar
16
+ `--format dot` y `--format json`, y solo el render de imagen falla con un
17
+ mensaje claro.
18
+ - Publicación automática en PyPI al empujar un tag `v*`, con verificación
19
+ posterior de la versión publicada.
20
+
21
+ ## [0.1.0] — 2026-10-21
22
+
23
+ ### Añadido
24
+
25
+ - Lectura de specs markdown con entidades, campos y modificadores `PK`, `UK`,
26
+ `FK -> tabla.columna`, `not null` y `null`.
27
+ - Cardinalidades inferidas del FK y sección opcional `## Relaciones` con
28
+ atajos `1:1`, `1:N` y `N:M`.
29
+ - Validación con diagnósticos `E0xx` y avisos `W0xx`, código de salida por
30
+ severidad.
31
+ - Render SVG y PNG con Graphviz: tablas con insignias, pata de cuervo y
32
+ etiquetas con el campo y la cardinalidad.
33
+ - Export `--format dot` y `--format json`, `--rankdir`, `--check` y
34
+ `--allow-no-pk`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jeironpro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,10 @@
1
+ # Archivos que entran al sdist; el wheel solo lleva el paquete y sus metadatos.
2
+ include LICENSE
3
+ include CHANGELOG.md
4
+ recursive-include examples *.md
5
+
6
+ # Fuera del sdist: tests, landing y configuración de CI
7
+ prune tests
8
+ prune landing
9
+ prune docs
10
+ prune .github
@@ -0,0 +1,277 @@
1
+ Metadata-Version: 2.4
2
+ Name: diagram-db
3
+ Version: 0.2.0
4
+ Summary: Genera diagramas entidad-relación con pata de cuervo a partir de un spec.md
5
+ Author: jeironpro
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/jeironpro/diagram-db
8
+ Project-URL: Documentation, https://jeironpro.github.io/diagram-db/
9
+ Project-URL: Repository, https://github.com/jeironpro/diagram-db
10
+ Project-URL: Issues, https://github.com/jeironpro/diagram-db/issues
11
+ Project-URL: Changelog, https://github.com/jeironpro/diagram-db/blob/main/CHANGELOG.md
12
+ Keywords: diagram,entity-relationship,erd,graphviz,markdown,schema,sql
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Documentation
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: graphviz<1.0,>=0.21
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=8.0; extra == "dev"
30
+ Requires-Dist: ruff>=0.16; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # diagram-db
34
+
35
+ Genera diagramas entidad-relación a partir de un `spec.md` en markdown.
36
+
37
+ Las entidades, sus campos y las claves PK/FK se declaran en el spec; la
38
+ herramienta valida el modelo (referencias, tipos, claves) y produce un diagrama
39
+ con pata de cuervo en SVG o PNG usando Graphviz. Sin base de datos, sin ORM y
40
+ sin servicios externos.
41
+
42
+ - Landing y [playground](https://jeironpro.github.io/diagram-db/) que ejecuta el
43
+ analizador real en el navegador.
44
+ - Paquete en [PyPI](https://pypi.org/project/diagram-db/).
45
+
46
+ ## Requisitos
47
+
48
+ - Python 3.10 o superior.
49
+ - Graphviz con el binario `dot` (`dnf install graphviz` / `apt install graphviz`).
50
+
51
+ ## Instalación
52
+
53
+ ```bash
54
+ pip install diagram-db
55
+ ```
56
+
57
+ Para trabajar sobre el código, con el entorno virtual del repo:
58
+
59
+ ```bash
60
+ python3 -m venv .venv
61
+ .venv/bin/pip install -r requirements.txt
62
+ .venv/bin/pip install -e .
63
+ ```
64
+
65
+ En los dos casos queda disponible el comando `diagram-db` y también
66
+ `python -m diagram_db`. Si falta el paquete `graphviz`, los formatos `dot` y
67
+ `json` siguen funcionando; solo la generación de imágenes falla con un mensaje
68
+ claro.
69
+
70
+ ## Uso
71
+
72
+ ```bash
73
+ diagram-db examples/tienda.spec.md -o salida/
74
+ # escribe salida/tienda.svg
75
+ ```
76
+
77
+ | Opción | Efecto |
78
+ |---|---|
79
+ | `-o, --output` | Directorio de salida, o archivo `.svg`/`.png` si se pide un solo formato |
80
+ | `--format` | `svg` (por defecto), `png`, `dot` o `json`; se combinan con comas |
81
+ | `--rankdir` | `TB` (por defecto), `LR`, `BT` o `RL` |
82
+ | `--check` | Solo valida el spec, sin escribir archivos |
83
+ | `--allow-no-pk` | Una entidad sin PK pasa de error a aviso |
84
+ | `--quiet` | Oculta avisos y mensajes de éxito |
85
+
86
+ Códigos de salida: `0` correcto, `1` errores en el spec, `2` error de uso.
87
+
88
+ ## Formato del spec
89
+
90
+ ```markdown
91
+ # Esquema: Tienda
92
+
93
+ ## Entidades
94
+
95
+ ### users
96
+ - id: int PK
97
+ - email: varchar(255) UK, not null
98
+ - manager_id: int FK -> users.id, null
99
+
100
+ ### products
101
+ - id: int PK
102
+ - sku: varchar(40) UK, not null
103
+ - price: decimal(10,2), not null
104
+
105
+ ### orders
106
+ - id: int PK
107
+ - user_id: int FK -> users.id, not null
108
+ - total: decimal(10,2), not null
109
+
110
+ ### order_items
111
+ - order_id: int PK, FK -> orders.id
112
+ - product_id: int PK, FK -> products.id
113
+ - qty: int, not null
114
+ ```
115
+
116
+ Reglas:
117
+
118
+ - `## Entidades` es obligatoria; lo que haya antes se ignora y el `# Título` se
119
+ usa como título del diagrama.
120
+ - Cada entidad es un `### nombre`. Los nombres con punto (por ejemplo
121
+ `sales.order`) se encierran en comillas invertidas dentro del encabezado.
122
+ - Cada campo es `- nombre: tipo` seguido de modificadores opcionales, en
123
+ cualquier orden y separados por comas o espacios.
124
+ - Las comas dentro de paréntesis no separan modificadores: `decimal(10,2)` se
125
+ conserva como un solo tipo.
126
+ - Los bloques de código y los comentarios `<!-- ... -->` se ignoran.
127
+ - Un campo es anulable por defecto; una PK siempre es obligatoria.
128
+
129
+ ### Modificadores
130
+
131
+ | Modificador | Alias | Efecto |
132
+ |---|---|---|
133
+ | `PK` | `pk` | Clave primaria; varias líneas forman una PK compuesta |
134
+ | `UK` | `uk`, `unique` | Clave única |
135
+ | `FK -> tabla.columna` | `fk` | Clave foránea; la columna es opcional si la PK destino es simple |
136
+ | `not null` | `nn` | Campo obligatorio |
137
+ | `null` | `nullable` | Fuerza la nulabilidad |
138
+
139
+ ### Cardinalidades
140
+
141
+ Se infieren del propio FK: si el campo es anulable el padre es opcional, y si
142
+ es `UK` la relación es 1:1. Una entidad cuya PK se compone solo de FK se dibuja
143
+ como tabla puente y sus aristas se etiquetan `N:M`.
144
+
145
+ Para sobrescribir una arista concreta, usa la sección opcional `## Relaciones`:
146
+
147
+ ```markdown
148
+ ## Relaciones
149
+
150
+ - users.manager_id: 0..1:N "reporta a"
151
+ - orders.user_id: 1:N "realiza"
152
+ ```
153
+
154
+ - `1:1`, `1:N` y `N:M` son atajos; la forma explícita es `<padre>:<hijo>`, con
155
+ `1` o `0..1` en el padre y `1`, `0..1`, `N`, `0..N` o `1..N` en el hijo.
156
+ - El texto entre comillas reemplaza el nombre del campo en la etiqueta; la
157
+ cardinalidad se sigue mostrando (`reporta a 0..1:N`).
158
+
159
+ ## Cómo leer el diagrama
160
+
161
+ - Cabecera con el nombre de la entidad y un filete terracota debajo; el
162
+ filete se vuelve rojizo si la entidad no declara PK.
163
+ - Insignias por columna: `PK`, `FK`, `UK`, combinables.
164
+ - `?` al final del tipo indica que el campo es anulable.
165
+ - Cada arista va del padre al hijo con el nombre del campo y su cardinalidad
166
+ al lado del punto medio, sin tapar la línea; las puntas terminan en el borde
167
+ de la tabla.
168
+ - Marcadores: `teetee` (doble barra) = exactamente uno, `odottee` (círculo y
169
+ barra) = cero o uno, `crow` = cero o muchos, `crowtee` = uno o muchos.
170
+
171
+ ## Diagnósticos
172
+
173
+ Cada problema se informa como `archivo:línea: CÓDIGO mensaje` por stderr. Los
174
+ errores impiden generar el diagrama; los avisos no.
175
+
176
+ | Código | Tipo | Cuándo aparece |
177
+ |---|---|---|
178
+ | E000 | error | Falta `## Entidades` |
179
+ | E001 | error | Entidad duplicada |
180
+ | E002 | error | Campo duplicado en la misma entidad |
181
+ | E003 | error | Entidad sin campos |
182
+ | E004 | error | FK a una entidad inexistente |
183
+ | E005 | error | FK a una columna inexistente |
184
+ | E006 | error | FK sin columna y la PK destino no es simple |
185
+ | E007 | error | Entidad sin PK |
186
+ | E008 | error | Línea no reconocida dentro de `## Entidades` |
187
+ | E009 | error | Nombre de entidad no válido |
188
+ | E010 | error | Nombre de campo no válido |
189
+ | E011 | error | Línea de campo sin `:` |
190
+ | E012 | error | Campo sin tipo |
191
+ | E013 | error | Modificador no reconocido |
192
+ | E020 | error | Línea de `## Relaciones` mal formada |
193
+ | E021 | error | La relación apunta a una entidad o campo inexistente |
194
+ | E022 | error | La relación apunta a un campo que no es FK |
195
+ | E023 | error | Cardinalidad no válida |
196
+ | E024 | error | Relación duplicada para el mismo FK |
197
+ | W001 | aviso | FK a una columna que no es PK ni UK |
198
+ | W002 | aviso | Tipo del FK distinto del tipo destino |
199
+ | W003 | aviso | Campo `PK` declarado como `null` (gana `PK`) |
200
+ | W004 | aviso | Entidad sin PK con `--allow-no-pk` |
201
+
202
+ ## Landing y playground
203
+
204
+ La web vive en [`landing/`](landing/index.html) y se publica en GitHub Pages. Es
205
+ HTML, CSS y JavaScript sin compilación; el playground descarga Pyodide solo
206
+ cuando se pide el primer análisis y ejecuta el mismo paquete que instala `pip`,
207
+ servido desde `landing/vendor/diagram_db`.
208
+
209
+ La publicación es un paso manual de una sola vez: activar Pages en
210
+ **Settings → Pages → Source: GitHub Actions** y definir la variable de
211
+ repositorio `PAGES_ENABLED=true`. Hasta entonces el workflow queda omitido, así
212
+ que `main` no falla mientras no esté activado.
213
+
214
+ Esa copia es la fuente única del playground y CI falla si diverge. Tras tocar
215
+ `src/diagram_db`, sincronízala:
216
+
217
+ ```bash
218
+ cp src/diagram_db/*.py landing/vendor/diagram_db/
219
+ ```
220
+
221
+ Para verla en local basta servir la carpeta:
222
+
223
+ ```bash
224
+ python3 -m http.server 8765 --directory landing
225
+ ```
226
+
227
+ ## Desarrollo
228
+
229
+ ```bash
230
+ .venv/bin/pip install -r test-requirements.txt
231
+ ruff check .
232
+ ruff format --check .
233
+ pre-commit run --all-files
234
+ .venv/bin/python -m pytest
235
+ ```
236
+
237
+ Las dependencias se gestionan con `pip-tools` a partir de `pyproject.toml`:
238
+
239
+ ```bash
240
+ pip-compile pyproject.toml -o requirements.txt
241
+ pip-compile --extra dev pyproject.toml -o test-requirements.txt
242
+ ```
243
+
244
+ CI (`.github/workflows/ci.yml`) corre Ruff, comprueba que la copia del playground
245
+ no diverja, pasa pytest en Python 3.10–3.13, construye el sdist y el wheel,
246
+ valida los metadatos con `twine check --strict` y prueba el wheel instalado en un
247
+ entorno limpio.
248
+
249
+ El release sale por tag `v*`: `.github/workflows/release.yml` corre los tests,
250
+ crea el GitHub Release con los artefactos, publica en PyPI con trusted
251
+ publishing (OIDC, sin tokens) y verifica que la versión instalada genera un
252
+ diagrama.
253
+
254
+ La landing se publica con `.github/workflows/pages.yml`, que queda omitido hasta
255
+ que Pages esté activado en el repositorio y la variable `PAGES_ENABLED` valga
256
+ `true`.
257
+
258
+ ## Publicación
259
+
260
+ La versión vive en `diagram_db.__version__` y `pyproject.toml` la lee de ahí, así
261
+ que un release es un tag:
262
+
263
+ ```bash
264
+ git tag v0.2.0 && git push origin v0.2.0
265
+ ```
266
+
267
+ El workflow de release corre los tests, crea el GitHub Release con los
268
+ artefactos, publica en PyPI con trusted publishing (OIDC, sin tokens) y verifica
269
+ que `pip install diagram-db==<versión>` genera un diagrama. El publisher se
270
+ configura una sola vez en <https://pypi.org/manage/account/publishing/> con el
271
+ repositorio `jeironpro/diagram-db`, el workflow `release.yml` y el entorno
272
+ `pypi`.
273
+
274
+ ## Licencia
275
+
276
+ Este proyecto está bajo la licencia **MIT**. Consulta el archivo
277
+ [LICENSE](LICENSE) para más detalles.
@@ -0,0 +1,245 @@
1
+ # diagram-db
2
+
3
+ Genera diagramas entidad-relación a partir de un `spec.md` en markdown.
4
+
5
+ Las entidades, sus campos y las claves PK/FK se declaran en el spec; la
6
+ herramienta valida el modelo (referencias, tipos, claves) y produce un diagrama
7
+ con pata de cuervo en SVG o PNG usando Graphviz. Sin base de datos, sin ORM y
8
+ sin servicios externos.
9
+
10
+ - Landing y [playground](https://jeironpro.github.io/diagram-db/) que ejecuta el
11
+ analizador real en el navegador.
12
+ - Paquete en [PyPI](https://pypi.org/project/diagram-db/).
13
+
14
+ ## Requisitos
15
+
16
+ - Python 3.10 o superior.
17
+ - Graphviz con el binario `dot` (`dnf install graphviz` / `apt install graphviz`).
18
+
19
+ ## Instalación
20
+
21
+ ```bash
22
+ pip install diagram-db
23
+ ```
24
+
25
+ Para trabajar sobre el código, con el entorno virtual del repo:
26
+
27
+ ```bash
28
+ python3 -m venv .venv
29
+ .venv/bin/pip install -r requirements.txt
30
+ .venv/bin/pip install -e .
31
+ ```
32
+
33
+ En los dos casos queda disponible el comando `diagram-db` y también
34
+ `python -m diagram_db`. Si falta el paquete `graphviz`, los formatos `dot` y
35
+ `json` siguen funcionando; solo la generación de imágenes falla con un mensaje
36
+ claro.
37
+
38
+ ## Uso
39
+
40
+ ```bash
41
+ diagram-db examples/tienda.spec.md -o salida/
42
+ # escribe salida/tienda.svg
43
+ ```
44
+
45
+ | Opción | Efecto |
46
+ |---|---|
47
+ | `-o, --output` | Directorio de salida, o archivo `.svg`/`.png` si se pide un solo formato |
48
+ | `--format` | `svg` (por defecto), `png`, `dot` o `json`; se combinan con comas |
49
+ | `--rankdir` | `TB` (por defecto), `LR`, `BT` o `RL` |
50
+ | `--check` | Solo valida el spec, sin escribir archivos |
51
+ | `--allow-no-pk` | Una entidad sin PK pasa de error a aviso |
52
+ | `--quiet` | Oculta avisos y mensajes de éxito |
53
+
54
+ Códigos de salida: `0` correcto, `1` errores en el spec, `2` error de uso.
55
+
56
+ ## Formato del spec
57
+
58
+ ```markdown
59
+ # Esquema: Tienda
60
+
61
+ ## Entidades
62
+
63
+ ### users
64
+ - id: int PK
65
+ - email: varchar(255) UK, not null
66
+ - manager_id: int FK -> users.id, null
67
+
68
+ ### products
69
+ - id: int PK
70
+ - sku: varchar(40) UK, not null
71
+ - price: decimal(10,2), not null
72
+
73
+ ### orders
74
+ - id: int PK
75
+ - user_id: int FK -> users.id, not null
76
+ - total: decimal(10,2), not null
77
+
78
+ ### order_items
79
+ - order_id: int PK, FK -> orders.id
80
+ - product_id: int PK, FK -> products.id
81
+ - qty: int, not null
82
+ ```
83
+
84
+ Reglas:
85
+
86
+ - `## Entidades` es obligatoria; lo que haya antes se ignora y el `# Título` se
87
+ usa como título del diagrama.
88
+ - Cada entidad es un `### nombre`. Los nombres con punto (por ejemplo
89
+ `sales.order`) se encierran en comillas invertidas dentro del encabezado.
90
+ - Cada campo es `- nombre: tipo` seguido de modificadores opcionales, en
91
+ cualquier orden y separados por comas o espacios.
92
+ - Las comas dentro de paréntesis no separan modificadores: `decimal(10,2)` se
93
+ conserva como un solo tipo.
94
+ - Los bloques de código y los comentarios `<!-- ... -->` se ignoran.
95
+ - Un campo es anulable por defecto; una PK siempre es obligatoria.
96
+
97
+ ### Modificadores
98
+
99
+ | Modificador | Alias | Efecto |
100
+ |---|---|---|
101
+ | `PK` | `pk` | Clave primaria; varias líneas forman una PK compuesta |
102
+ | `UK` | `uk`, `unique` | Clave única |
103
+ | `FK -> tabla.columna` | `fk` | Clave foránea; la columna es opcional si la PK destino es simple |
104
+ | `not null` | `nn` | Campo obligatorio |
105
+ | `null` | `nullable` | Fuerza la nulabilidad |
106
+
107
+ ### Cardinalidades
108
+
109
+ Se infieren del propio FK: si el campo es anulable el padre es opcional, y si
110
+ es `UK` la relación es 1:1. Una entidad cuya PK se compone solo de FK se dibuja
111
+ como tabla puente y sus aristas se etiquetan `N:M`.
112
+
113
+ Para sobrescribir una arista concreta, usa la sección opcional `## Relaciones`:
114
+
115
+ ```markdown
116
+ ## Relaciones
117
+
118
+ - users.manager_id: 0..1:N "reporta a"
119
+ - orders.user_id: 1:N "realiza"
120
+ ```
121
+
122
+ - `1:1`, `1:N` y `N:M` son atajos; la forma explícita es `<padre>:<hijo>`, con
123
+ `1` o `0..1` en el padre y `1`, `0..1`, `N`, `0..N` o `1..N` en el hijo.
124
+ - El texto entre comillas reemplaza el nombre del campo en la etiqueta; la
125
+ cardinalidad se sigue mostrando (`reporta a 0..1:N`).
126
+
127
+ ## Cómo leer el diagrama
128
+
129
+ - Cabecera con el nombre de la entidad y un filete terracota debajo; el
130
+ filete se vuelve rojizo si la entidad no declara PK.
131
+ - Insignias por columna: `PK`, `FK`, `UK`, combinables.
132
+ - `?` al final del tipo indica que el campo es anulable.
133
+ - Cada arista va del padre al hijo con el nombre del campo y su cardinalidad
134
+ al lado del punto medio, sin tapar la línea; las puntas terminan en el borde
135
+ de la tabla.
136
+ - Marcadores: `teetee` (doble barra) = exactamente uno, `odottee` (círculo y
137
+ barra) = cero o uno, `crow` = cero o muchos, `crowtee` = uno o muchos.
138
+
139
+ ## Diagnósticos
140
+
141
+ Cada problema se informa como `archivo:línea: CÓDIGO mensaje` por stderr. Los
142
+ errores impiden generar el diagrama; los avisos no.
143
+
144
+ | Código | Tipo | Cuándo aparece |
145
+ |---|---|---|
146
+ | E000 | error | Falta `## Entidades` |
147
+ | E001 | error | Entidad duplicada |
148
+ | E002 | error | Campo duplicado en la misma entidad |
149
+ | E003 | error | Entidad sin campos |
150
+ | E004 | error | FK a una entidad inexistente |
151
+ | E005 | error | FK a una columna inexistente |
152
+ | E006 | error | FK sin columna y la PK destino no es simple |
153
+ | E007 | error | Entidad sin PK |
154
+ | E008 | error | Línea no reconocida dentro de `## Entidades` |
155
+ | E009 | error | Nombre de entidad no válido |
156
+ | E010 | error | Nombre de campo no válido |
157
+ | E011 | error | Línea de campo sin `:` |
158
+ | E012 | error | Campo sin tipo |
159
+ | E013 | error | Modificador no reconocido |
160
+ | E020 | error | Línea de `## Relaciones` mal formada |
161
+ | E021 | error | La relación apunta a una entidad o campo inexistente |
162
+ | E022 | error | La relación apunta a un campo que no es FK |
163
+ | E023 | error | Cardinalidad no válida |
164
+ | E024 | error | Relación duplicada para el mismo FK |
165
+ | W001 | aviso | FK a una columna que no es PK ni UK |
166
+ | W002 | aviso | Tipo del FK distinto del tipo destino |
167
+ | W003 | aviso | Campo `PK` declarado como `null` (gana `PK`) |
168
+ | W004 | aviso | Entidad sin PK con `--allow-no-pk` |
169
+
170
+ ## Landing y playground
171
+
172
+ La web vive en [`landing/`](landing/index.html) y se publica en GitHub Pages. Es
173
+ HTML, CSS y JavaScript sin compilación; el playground descarga Pyodide solo
174
+ cuando se pide el primer análisis y ejecuta el mismo paquete que instala `pip`,
175
+ servido desde `landing/vendor/diagram_db`.
176
+
177
+ La publicación es un paso manual de una sola vez: activar Pages en
178
+ **Settings → Pages → Source: GitHub Actions** y definir la variable de
179
+ repositorio `PAGES_ENABLED=true`. Hasta entonces el workflow queda omitido, así
180
+ que `main` no falla mientras no esté activado.
181
+
182
+ Esa copia es la fuente única del playground y CI falla si diverge. Tras tocar
183
+ `src/diagram_db`, sincronízala:
184
+
185
+ ```bash
186
+ cp src/diagram_db/*.py landing/vendor/diagram_db/
187
+ ```
188
+
189
+ Para verla en local basta servir la carpeta:
190
+
191
+ ```bash
192
+ python3 -m http.server 8765 --directory landing
193
+ ```
194
+
195
+ ## Desarrollo
196
+
197
+ ```bash
198
+ .venv/bin/pip install -r test-requirements.txt
199
+ ruff check .
200
+ ruff format --check .
201
+ pre-commit run --all-files
202
+ .venv/bin/python -m pytest
203
+ ```
204
+
205
+ Las dependencias se gestionan con `pip-tools` a partir de `pyproject.toml`:
206
+
207
+ ```bash
208
+ pip-compile pyproject.toml -o requirements.txt
209
+ pip-compile --extra dev pyproject.toml -o test-requirements.txt
210
+ ```
211
+
212
+ CI (`.github/workflows/ci.yml`) corre Ruff, comprueba que la copia del playground
213
+ no diverja, pasa pytest en Python 3.10–3.13, construye el sdist y el wheel,
214
+ valida los metadatos con `twine check --strict` y prueba el wheel instalado en un
215
+ entorno limpio.
216
+
217
+ El release sale por tag `v*`: `.github/workflows/release.yml` corre los tests,
218
+ crea el GitHub Release con los artefactos, publica en PyPI con trusted
219
+ publishing (OIDC, sin tokens) y verifica que la versión instalada genera un
220
+ diagrama.
221
+
222
+ La landing se publica con `.github/workflows/pages.yml`, que queda omitido hasta
223
+ que Pages esté activado en el repositorio y la variable `PAGES_ENABLED` valga
224
+ `true`.
225
+
226
+ ## Publicación
227
+
228
+ La versión vive en `diagram_db.__version__` y `pyproject.toml` la lee de ahí, así
229
+ que un release es un tag:
230
+
231
+ ```bash
232
+ git tag v0.2.0 && git push origin v0.2.0
233
+ ```
234
+
235
+ El workflow de release corre los tests, crea el GitHub Release con los
236
+ artefactos, publica en PyPI con trusted publishing (OIDC, sin tokens) y verifica
237
+ que `pip install diagram-db==<versión>` genera un diagrama. El publisher se
238
+ configura una sola vez en <https://pypi.org/manage/account/publishing/> con el
239
+ repositorio `jeironpro/diagram-db`, el workflow `release.yml` y el entorno
240
+ `pypi`.
241
+
242
+ ## Licencia
243
+
244
+ Este proyecto está bajo la licencia **MIT**. Consulta el archivo
245
+ [LICENSE](LICENSE) para más detalles.
@@ -0,0 +1,36 @@
1
+ # Esquema: Biblioteca
2
+
3
+ Catálogo mínimo: quién escribe, qué se presta y quién lo recibe.
4
+
5
+ ## Entidades
6
+
7
+ ### autores
8
+ - id: int PK
9
+ - nombre: varchar(120), not null
10
+ - pais: varchar(60)
11
+
12
+ ### libros
13
+ - id: int PK
14
+ - autor_id: int FK -> autores.id, not null
15
+ - titulo: varchar(200), not null
16
+ - isbn: varchar(20) UK, not null
17
+ - anio: int, not null
18
+
19
+ ### socios
20
+ - id: int PK
21
+ - nombre: varchar(120), not null
22
+ - correo: varchar(150) UK, not null
23
+ - alta: date, not null
24
+
25
+ ### prestamos
26
+ - id: int PK
27
+ - libro_id: int FK -> libros.id, not null
28
+ - socio_id: int FK -> socios.id, not null
29
+ - retirado: date, not null
30
+ - devuelto: date
31
+
32
+ ## Relaciones
33
+
34
+ - libros.autor_id: 1:N "escribe"
35
+ - prestamos.libro_id: 1:N "presta"
36
+ - prestamos.socio_id: 1:N "recibe"
@@ -0,0 +1,71 @@
1
+ # Esquema: Préstamos Taveras
2
+
3
+ Sistema de préstamos semanales. Lo que está fuera de `## Entidades` no se
4
+ interpreta: sirve para documentar decisiones del modelo.
5
+
6
+ Convenciones:
7
+
8
+ - `uuid` es un hash SHA-256 en hexadecimal (64 caracteres) y actúa como clave
9
+ pública de cada tabla; `id` es la clave primaria interna.
10
+ - `pagos.empleado_id` referencia a un usuario con rol EMPLEADO. El diagrama no
11
+ puede expresar ese filtro: la columna guarda el id, no el rol.
12
+
13
+ ## Entidades
14
+
15
+ ### usuarios
16
+ - id: int PK
17
+ - uuid: char(64) UK, not null
18
+ - rol: enum(ADMIN, CLIENTE, EMPLEADO), not null
19
+ - nombre: varchar(100), not null
20
+ - apellidos: varchar(100), not null
21
+ - cedula: varchar(20) UK, not null
22
+ - correo: varchar(150) UK, not null
23
+ - contrasena: varchar(255), not null
24
+ - telefono: varchar(20)
25
+ - direccion: varchar(200)
26
+
27
+ ### prestamos
28
+ - id: int PK
29
+ - uuid: char(64) UK, not null
30
+ - usuario_id: int FK -> usuarios.id, not null
31
+ - monto: decimal(12,2), not null
32
+ - monto_cuota: decimal(12,2), not null
33
+ - monto_mora: decimal(12,2), not null
34
+ - cantidad_semanas: int, not null
35
+ - dia_pago: enum(LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO), not null
36
+
37
+ ### semanas_prestamo
38
+ - id: int PK
39
+ - uuid: char(64) UK, not null
40
+ - prestamo_id: int FK -> prestamos.id, not null
41
+ - numero_semana: int, not null
42
+ - monto: decimal(12,2), not null
43
+ - estado: enum(PAGADA, PENDIENTE, CANCELADA), not null
44
+ - fecha: date, not null
45
+
46
+ ### pagos
47
+ - id: int PK
48
+ - uuid: char(64) UK, not null
49
+ - semanas_prestamo_id: int FK -> semanas_prestamo.id, not null
50
+ - monto: decimal(12,2), not null
51
+ - fecha: date, not null
52
+ - tipo: enum(CUOTA, MORA, AMBOS), not null
53
+ - metodo_pago: enum(EFECTIVO, TRANSFERENCIA), not null
54
+ - empleado_id: int FK -> usuarios.id, not null
55
+
56
+ ### moras
57
+ - id: int PK
58
+ - uuid: char(64) UK, not null
59
+ - semanas_prestamo_id: int FK -> semanas_prestamo.id, not null
60
+ - monto: decimal(12,2), not null
61
+ - fecha: date, not null
62
+ - estado: enum(PAGADA, PENDIENTE, CANCELADA), not null
63
+ - metodo_pago: enum(EFECTIVO, TRANSFERENCIA)
64
+
65
+ ## Relaciones
66
+
67
+ - prestamos.usuario_id: 1:N "solicita"
68
+ - semanas_prestamo.prestamo_id: 1:N "tiene"
69
+ - pagos.semanas_prestamo_id: 1:N "cubre"
70
+ - moras.semanas_prestamo_id: 1:N "genera"
71
+ - pagos.empleado_id: 1:N "registra"