Svelte Commerce
SvelteKit으로 만든 독립형 오픈소스 스토어프론트, 26개 상거래 백엔드와 헤드리스 연동, MIT 라이선스
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Sitio web, trazabilidad de lotes y generador de etiquetas para imprimir de SaborPuro, la mermelada de mora elaborada por Mujeres Usmeñas en Usme, Bogotá D.C.
Sirve a dos públicos: a quien compra el frasco, que puede ver cómo se hizo, entender qué dice cada campo de la etiqueta y verificar su lote; y a quien produce, que planea cada tanda e imprime etiquetas que cumplen el rotulado colombiano sin hacer cuentas a mano.
Demo en vivo: https://saborpuro.lat (también en https://saborpuro.vercel.app)
Sitio público (/)
L261018-01) consulta en la API
qué día se produjo la tanda, con qué proporciones y hasta cuándo rinde.prefers-reduced-motion.Generador de etiquetas (/etiquetas)
API de trazabilidad (apps/api)
POST /api/lotes) y devuelve el lote, su etiqueta y su
código de barras en SVG.X-Clave.| La etiqueta, campo por campo | Planeador de tandas |
|---|---|
| Generador de etiquetas | En el celular |
|---|---|
Capturas tomadas del sitio en vivo con Playwright (1280 × 800 y 390 × 844).
| Parte | Tecnología |
|---|---|
Web (apps/web) | Next.js 15 (App Router), React 19, JavaScript y CSS propio, sin framework de estilos. Fuentes Fraunces, Karla y JetBrains Mono. |
API (apps/api) | Fastify 5, @fastify/cors y PostgreSQL con pg. Las tablas (lotes, pedidos, etiquetas) se crean solas al arrancar. |
Lógica compartida (packages/brand) | JavaScript ESM sin dependencias. Next lo transpila con transpilePackages. |
| Pruebas | node:test, el corredor nativo de Node. |
| Infraestructura | Vercel (web) y Railway con Nixpacks (API y Postgres). Monorepo con npm workspaces, Node 22. |
apps/web Next.js 15 — sitio público y generador → Vercel
apps/api Fastify + PostgreSQL — trazabilidad → Railway
packages/brand Lógica compartida y tokens de marca
packages/brand es el corazón del proyecto:
| Módulo | Qué hace |
|---|---|
tokens.js | Identidad de marca y datos legales. Archivo único de configuración. |
barcode.js | EAN-13: generación, validación, dígito verificador y render SVG. |
lote.js | Códigos de lote, fechas de producción y vencimiento. |
nutricional.js | Perfil nutricional desde la receta y evaluación de sellos frontales. |
etiqueta.js | Arma la etiqueta completa y valida campos obligatorios. |
plantilla.js | Plantilla editable del generador: tamaños, hojas, capacidad por hoja y validación. |
Para cambiar el nombre, los colores, el NIT o el registro sanitario, se
toca solo packages/brand/src/tokens.js: todo lo demás se actualiza
con él.
Datos de ejemplo.
tokens.jstrae a propósito datos de relleno («Fabricante de ejemplo», «Calle Falsa 123», teléfono300 000 0000, NIT y registro con ceros): ningún dato personal real vive en el repositorio. Los de verdad se escriben en el generador y se guardan con cada etiqueta en el servidor.
Requisitos: Node 22 (está en .nvmrc; el mínimo es 20) y npm. PostgreSQL solo
hace falta para la verificación de lotes y el catálogo de productos.
git clone https://github.com/ronalc90/chela
cd chela
npm ci
npm run dev:web # http://localhost:3000
Con eso funcionan el sitio público, el planeador y el generador (el borrador queda en el navegador). Sin API, la verificación de lotes avisa que el servicio no está conectado.
Para tener también la API:
# Postgres local (por ejemplo, con Docker)
docker run -d --name chela-pg -e POSTGRES_PASSWORD=chela -p 5432:5432 postgres:16
# API en http://localhost:8080; crea las tablas al arrancar
DATABASE_URL="postgres://postgres:chela@localhost:5432/postgres?sslmode=disable" \
ETIQUETAS_CLAVE="clave-local" \
npm run dev:api
# Web apuntando a esa API
printf 'NEXT_PUBLIC_API_URL=http://localhost:8080\nETIQUETAS_CLAVE=clave-local\n' > apps/web/.env.local
npm run dev:web
sslmode=disable apaga TLS para la base local. Sin CORS_ORIGINS, la API
acepta cualquier origen.
Desde la raíz del repositorio:
| Script | Qué hace |
|---|---|
npm run dev:web | Servidor de desarrollo de Next.js en el puerto 3000. |
npm run dev:api | API con node --watch en el puerto 8080 (o PORT). |
npm run build:web | Compilación de producción de la web (next build). |
npm run build:api | La API no tiene paso de compilación (Node ejecuta src/ directo) y no define build, así que este script falla. |
npm test | Las 20 pruebas de packages/brand. |
npm run start --workspace=@chela/api | Arranca la API en modo producción; es lo que ejecuta Railway. |
npm run start --workspace=@chela/web | Sirve la web ya compilada (next start). |
npm test
Son 20 pruebas con node:test sobre la lógica compartida; no necesitan
instalar dependencias ni base de datos.
packages/brand/test/core.test.mjs (13): dígito verificador y estructura del
EAN-13, render SVG, lote de ida y vuelta, vencimiento a fin de mes, perfil
nutricional, sello de azúcares y armado y validación de la etiqueta.packages/brand/test/plantilla.test.mjs (7): plantilla por defecto,
normalización y límites, tamaños predefinidos, lote y vencimiento manuales,
sellos y EAN propio, campos obligatorios y capacidad por hoja (A4, Carta y
horizontal).La web y la API no tienen pruebas automáticas.
En GitHub Actions (.github/workflows/ci.yml), cada PR y cada push a main
corren con Node 22 npm ci, npm test, npm run build:web y una
comprobación de sintaxis de apps/api.
Web → Vercel. Proyecto saborpuro (framework Next.js, Node 22), con los
dominios saborpuro.lat, www.saborpuro.lat y saborpuro.vercel.app. Cada
cambio en main se publica en producción y cada PR tiene su vista previa.
Variables: NEXT_PUBLIC_API_URL y, opcional, ETIQUETAS_CLAVE.
API → Railway. railway.json y nixpacks.toml definen el despliegue: Node
22 con Nixpacks, instalación de los workspaces, arranque con
npm run start --workspace=@chela/api, chequeo de salud en /health y
reinicio automático si falla. Railway enlaza Postgres e inyecta
DATABASE_URL.
apps/web
| Variable | Para qué |
|---|---|
NEXT_PUBLIC_API_URL | URL pública de la API en Railway. Sin ella, la verificación de lote avisa que el servicio no está conectado. |
ETIQUETAS_CLAVE | Secreto de servidor, sin prefijo NEXT_PUBLIC_. Si está, el puente /api/etiquetas pone la clave por su cuenta y la biblioteca abre sin pedir nada; entonces cualquiera que abra el sitio puede ver, editar y borrar las etiquetas. Si no está, la biblioteca pide la clave y la guarda en ese navegador. |
apps/api
| Variable | Para qué |
|---|---|
DATABASE_URL | Postgres. Railway la inyecta al enlazar el servicio. Sin ella la API arranca, pero los endpoints de datos fallan. |
CORS_ORIGINS | Orígenes permitidos, separados por coma. Los *.vercel.app se permiten siempre. |
ETIQUETAS_CLAVE | Clave de /api/etiquetas, comparada contra la cabecera X-Clave. Sin ella esas rutas responden 503 en vez de quedar abiertas. |
PORT | Lo asigna Railway. En local, 8080 por defecto. |
LOG_LEVEL | Nivel de los logs de Fastify (info por defecto). |
Cada producto guardado es su rótulo completo (ver @chela/brand/plantilla) más
una foto opcional. La foto no se imprime: sirve para reconocerlo en el
catálogo de /etiquetas. Se redimensiona y se recomprime a JPEG en el
navegador antes de subirla (máximo 900 KB), y se guarda además una miniatura
(máximo 80 KB) que es la única que viaja en el listado.
En /etiquetas, tras configurar la tanda, usa el botón de imprimir y en
el diálogo del navegador desactiva «ajustar a la página» y deja la
escala en 100 %. Las etiquetas están medidas en milímetros, así que
cualquier reescalado las saca de tamaño.
La hoja imprime solo las etiquetas: el panel, el menú y los fondos se ocultan automáticamente.
La etiqueta sigue:
La mermelada lleva sello «EXCESO EN AZÚCARES». El umbral es 10 % o más de la energía total proveniente de azúcares libres, y una mermelada tradicional lo supera con holgura. Llevar un sello prohíbe toda declaración de propiedad nutricional o de salud en la etiqueta.
El código de barras actual no sirve para retail. Usa prefijo interno
200, válido para control propio. Un GTIN comercial lo asigna GS1
Colombia (LOGYCA); el prefijo de país es 770.
Los valores reales de teléfono, NIT y registro no se escriben en el repositorio: van en el generador. El generador marca en pantalla los campos que siguen pendientes.
Los valores nutricionales del sitio son estimaciones calculadas desde la receta. No sustituyen un análisis de laboratorio.