home
  • Spanish (ES)
  • English (UK)
  • Portuguese (PT)
  • star Destacados
  • Hermes Agent
  • draw Proyectos UX
  • person Sobre mí
  • mail Contacto
arrow_back Volver al proyecto Inicio

Documentación del proyecto

Documentación · Lista de la compra

11 archivos markdown (producto, arquitectura, API, auth, datos, deploy…).

En esta página Visión general 0% expand_more
Visión general Enlaces Stack Producto y features Problema Solución Características Despensa Lista Urgente Categorías y unidades Ajustes Offline-first Android Arquitectura Diagrama lógico Capas Flujo de estado Estructura del proyecto Superficie API Neon En producción (same-origin) En desarrollo Operaciones de producto Autenticación email + Neon Flujo Guards Seguridad Modelo de datos Offline (SQLite / sql.js) Tipo (src/app/core/types/product.ts) Nube Deploy Netlify Idea Config (netlify.toml) Android Decisiones de producto y tech SQLite en el navegador, no JSON suelto Neon Auth/Data en lugar de Nest propio Proxy Netlify same-origin Tres tabs, no una lista infinita Signals + effect para persistir Retos y resultados No guardar vacío al arrancar Cookie de sesión en PWA iOS Convergencia local ↔ nube WASM de SQLite en el bundle Resultado Angular en Lista de la compra Qué se aplica Techo de esta era

01-overview.md

Visión general · Lista de la compra

Lista de la compra (repo listacompra) es una Progressive Web App de lista de supermercado: despensa, lista pendiente y urgente. Funciona offline con SQLite en el navegador (sql.js + IndexedDB) y, si el usuario abre sesión, sincroniza a Neon Auth + Data API.

Es una sola app Angular/Ionic (no monorepo Nest). En producción Netlify sirve www/ y hace proxy same-origin de /__neon-auth/* y /__neon-data/* para que la cookie sea first-party (iOS Safari / PWA).

Enlaces

  • Web: https://lalistadelacompra.netlify.app
  • GitHub: Criscode2022/listacompra
  • CI: GitHub Actions ci.yml

Stack

CapaTecnología
WebAngular 17.3, Ionic 7, Capacitor 5, Tailwind 3, Signals
Offlinesql.js (SQLite WASM) persistido en IndexedDB (listacompra.sqlite)
NubeNeon Auth + Neon Data API (@neondatabase/neon-js)
ExtrajsPDF (export de la lista), Material snackbars
DeployNetlify (www/ + SPA rewrite + proxy /__neon-*)

02-product.md

Producto y features

Problema

Las listas del súper viven en notas, WhatsApp o papel. Se pierden las cantidades, no hay urgentes separados, y al llegar a la tienda no hay un PDF imprimible agrupado por pasillo. Las apps de recetas o de supermercado piden cuenta desde el primer tap.

Solución

PWA instalable con tres tabs: Despensa (inventario), Lista (pendientes + PDF) y Urgente. Offline-first en SQLite. Sync opt-in con Neon Auth (email verificado) y Data API.

Características

Despensa

Inventario completo. FAB abre el modal de alta (nombre, cantidad, unidad, categoría). Checkbox marca comprado.

Lista

Solo productos pendientes. Chips de categoría con contador, búsqueda, checkbox y exportar PDF (jsPDF, agrupado por categoría, con fecha).

Urgente

Misma mecánica, filtrada a urgent: true. FAB rojo para crear ya marcado como urgente.

Categorías y unidades

Once categorías (frutas, verduras, carnes, pescados, lácteos, panadería, bebidas, limpieza, higiene, congelados, otros) y unidades ud | kg | g | l | ml | oz | lb.

Ajustes

Modo básico (oculta categoría), modo online/offline, cuenta Neon, vaciar almacenamiento.

Offline-first

Sin red se puede crear, tachar y exportar. La nube es continuidad entre dispositivos.

Android

Capacitor 5 (npx cap sync android) sobre el mismo www/.

03-architecture.md

Arquitectura

Diagrama lógico

Browser / PWA Ionic (Angular 17)
    │  offline: sql.js → IndexedDB
    │  online + sesión: Neon JS client
    ▼
Same-origin  /__neon-auth/*  y  /__neon-data/*
    │  (Netlify reverse proxy)
    ▼
Neon Auth  +  Neon Data API  ──►  Postgres (proyecto icy-silence-71895789)

Capas

  1. Cliente — Tabs Ionic: Despensa, Lista, Urgente. Settings (FAB) y Auth fuera de la tab bar. Servicios: DataService, SqliteService, NeonService, CloudSyncService, AppModeService.
  2. Offline — SQLite en memoria (sql.js); tras cada write se exporta el fichero a IndexedDB (listacompra.sqlite). Ver docs/SQLITE.md.
  3. Nube — @neondatabase/neon-js: Auth email/password y Data API de productos + settings. No hay Nest propio.
  4. Deploy — Netlify sirve www/ y reescribe /__neon-* al host Neon.

Flujo de estado

  1. SqliteService.open() restaura el DB file.
  2. DataService carga products y basicMode en signals.
  3. Un effect persiste cada cambio y dispara syncCallback si hay sesión.
  4. Las tabs leen dataService.products() y filtran (pendiente / urgente / categoría).

04-monorepo.md

Estructura (app única)

Lista de la compra no es un monorepo Turborepo: un solo paquete Angular/Ionic.

PathRol
src/app/tabs/tab-pantryTab Despensa
src/app/tabs/tab-listTab Lista + PDF
src/app/tabs/tab-urgentTab Urgente
src/app/layout/add-product-modalAlta de producto
src/app/layout/headerCabecera compartida
src/app/settingsAjustes
src/app/authSign-in / sign-up
src/app/core/services/data-serviceSignals + persistencia
src/app/core/services/sqlitesql.js + IndexedDB
src/app/core/services/neonCliente Auth/Data
src/app/core/services/cloud-syncPush/pull
src/assets/sql-wasm.*Runtime SQLite WASM
docs/SQLITE.mdCómo se guarda el .sqlite
netlify.tomlBuild + proxy Neon + SPA

05-api.md

Superficie API (Neon Auth + Data)

No hay Nest propio. El cliente habla con Neon a través de @neondatabase/neon-js.

En producción (same-origin)

PrefijoDestino (Netlify rewrite 200)
/__neon-auth/*Neon Auth (*.neonauth.*.aws.neon.tech/neondb/auth)
/__neon-data/*Neon Data API REST v1 (*.apirest.*.aws.neon.tech/neondb/rest/v1)

environment.prod.ts usa neonAuthUrl: '/__neon-auth' y neonDataApiUrl: '/__neon-data'. Proyecto Neon: icy-silence-71895789.

En desarrollo

environment.ts apunta a las URLs absolutas de Neon (sin proxy).

Operaciones de producto

CloudSyncService sube y baja:

  • Filas de products (nombre, checked, quantity, urgent, unit, category) por user_id
  • Settings (basic_mode)

Tras registro se sube lo local. Tras login, la nube reemplaza lo del dispositivo.

06-auth.md

Modelo de autenticación

Flujo

  1. En Ajustes, el usuario activa modo online → /auth.
  2. Crea cuenta (nombre, email, contraseña) o inicia sesión.
  3. Neon Auth (client.auth.signUp.email / signIn.email).
  4. Verificación de email antes de poder entrar.
  5. getSession() calienta la caché. OnlineAuthGuard deja pasar si el modo es offline.
  6. Logout: signOut(). El SQLite local se conserva.

Guards

  • OnlineAuthGuard — si isOnline() y no hay sesión → /auth.
  • GuestAuthGuard — si ya hay sesión, saca al usuario de /auth.

Seguridad

  • Contraseña y tokens los gestiona Neon Auth.
  • Proxy same-origin para no perder la sesión por ITP.
  • Cloud sync opt-in.

07-data-model.md

Modelo de datos

Offline (SQLite / sql.js)

Tablas en el fichero listacompra.sqlite (IndexedDB):

TablaContenido
productsname, checked, quantity, urgent, unit, category
app_settingsclave/valor (basicMode)

Tipo (src/app/core/types/product.ts)

interface Product {
  name: string;
  checked: boolean;
  quantity: number;
  urgent: boolean;
  unit: MeasureUnit;       // ud | kg | g | l | ml | oz | lb
  category: ProductCategory;
}

ProductCategory: frutas, verduras, carnes, pescados, lácteos, panadería, bebidas, limpieza, higiene, congelados, otros.

La clave de producto en UI es el nombre (toggleStatus(productName), delete(productName)).

Nube

Mismas columnas + user_id. Settings: basic_mode.

08-deploy-vercel.md

Deploy en Netlify

Idea

  • Build Angular → www/
  • Catch-all SPA: /* → /index.html 200
  • Proxy Neon antes del catch-all

Config (netlify.toml)

[build]
  publish = "www"
  command = "npm run build"

[[redirects]]
  from = "/__neon-auth/*"
  to = "https://<host>.neonauth.../neondb/auth/:splat"
  status = 200
  force = true

[[redirects]]
  from = "/__neon-data/*"
  to = "https://<host>.apirest.../neondb/rest/v1/:splat"
  status = 200
  force = true

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Live: lalistadelacompra.netlify.app.

Android

npm run build
npx cap sync android
npx cap open android

webDir de Capacitor apunta a www/.

09-decisions.md

Decisiones

SQLite en el navegador, no JSON suelto

sql.js da tablas y queries reales (ORDER BY name COLLATE NOCASE) y un único fichero exportable. Ionic Storage se usó al principio; el servicio actual persiste el .sqlite en IndexedDB.

Neon Auth/Data en lugar de Nest propio

El contrato (email, sesión, filas por usuario) cabe en Neon. Un segundo servicio no aportaba ownership custom como el PIN de Task Cloud.

Proxy Netlify same-origin

Sin proxy, la cookie de Auth es third-party y iOS/PWA la tiran.

Tres tabs, no una lista infinita

Despensa / Lista / Urgente es el modelo mental del súper: lo que hay, lo que falta, lo que no puede esperar. El PDF sale de la Lista (pendientes), no de la despensa.

Signals + effect para persistir

Cada mutación actualiza products; el effect escribe SQLite y agenda sync. Evita save() manual en cada tap.

10-challenges-results.md

Retos y aprendizajes

No guardar vacío al arrancar

DataService tiene ready = false hasta el primer load(). Sin eso, el effect de signals persistiría [] y borraría la despensa en cada refresh.

Cookie de sesión en PWA iOS

Mismo problema que Presencia: ITP. Solución: rewrite /__neon-* same-origin.

Convergencia local ↔ nube

Tras login, la nube sustituye lo local. Tras registro, se sube lo que ya había. Evita merges de dos despensas distintas.

WASM de SQLite en el bundle

sql-wasm.js + sql-wasm.wasm viven en src/assets/ para que el Service Worker y Netlify los sirvan como estáticos. Sin eso, sql.js no arranca offline.

Resultado

PWA usable en el pasillo sin red, PDF para quien aún imprime la lista, y cuenta opcional si hay dos dispositivos en casa.

11-angular-skill.md

Angular en Lista de la compra

App Angular 17.3 + Ionic 7 + TypeScript 5.4 + Zone. Estado con Signals (products, basicMode, filtros de tab). No hay skill Angular versionada en este repo.

Qué se aplica

PrácticaDónde
Signals + effectDataService persistencia automática
Computed en tabspendingProducts(), categoryCounts(), textFilter()
Modal IonicAddProductModalComponent
GuardsOnlineAuthGuard, GuestAuthGuard
Service workerPWA (ngsw-config.json)
TestsKarma + Jasmine (npm run test:ci)

Techo de esta era

Ionic 7 + Angular 17: Zone obligatorio, sin Signal Forms de v21+. Los formularios del modal son ngModel. Subir a Angular 21/22 exigiría alinear Ionic (ver techo v22×Ionic en Task Cloud / Presencia).

En esta página

Visión general Enlaces Stack Producto y features Problema Solución Características Despensa Lista Urgente Categorías y unidades Ajustes Offline-first Android Arquitectura Diagrama lógico Capas Flujo de estado Estructura del proyecto Superficie API Neon En producción (same-origin) En desarrollo Operaciones de producto Autenticación email + Neon Flujo Guards Seguridad Modelo de datos Offline (SQLite / sql.js) Tipo (src/app/core/types/product.ts) Nube Deploy Netlify Idea Config (netlify.toml) Android Decisiones de producto y tech SQLite en el navegador, no JSON suelto Neon Auth/Data en lugar de Nest propio Proxy Netlify same-origin Tres tabs, no una lista infinita Signals + effect para persistir Retos y resultados No guardar vacío al arrancar Cookie de sesión en PWA iOS Convergencia local ↔ nube WASM de SQLite en el bundle Resultado Angular en Lista de la compra Qué se aplica Techo de esta era

0% leído

folder_zip Descargar todos (ZIP)
Hermes Agent