Qué hay, cuánto queda y quién sacó cosas de bodega.
Dos pantallas: la bodega, con el stock y los botones de sacar y reponer, y el libro de movimientos.
Corre en sube, que le pone la base de datos, el dominio, el TLS y el inicio de sesión. La app no trae código de autenticación.
Porque hay una columna que esta app no tiene, y no tenerla es toda la diferencia:
// esto NO está en el esquema
stock: integer('stock').notNull()El stock es la suma de los movimientos, calculada al leer:
stock: sql<number>`coalesce(sum(${movements.delta}), 0)::int`Con una columna stock hay que leerla, cambiarla y escribirla de vuelta. Dos
personas sacando las últimas tres cajas al mismo tiempo leen 3 las dos,
escriben 2 las dos, y una de las salidas desaparece: el conteo queda malo y
nada en los datos dice que pasó. Dos insert no se pisan.
Además contesta la pregunta que la app recibe de verdad, que no es "cuántos
hay" sino "quién se los llevó". La tabla movements no se edita nunca, y por
eso sigue contestando un mes después.
El precio es real y conviene decirlo: cada lectura suma. Con miles de movimientos por producto hay que materializar el total en alguna parte — pero eso es una optimización que se hace cuando duele, y se hace sobre el libro, que sigue siendo la verdad.
No está bloqueado a propósito. Un stock negativo significa que la repisa y el libro no coinciden, y esconderlo detrás de un error de validación solo mueve el problema al día en que alguien necesita el producto. Sale en rojo, que es la única fila de la página que vale la pena ir a mirar.
npm install
npm run buildConstruye sin base de datos. Para verlo con datos hay que desplegarlo:
npm i -g @sube.sh/cli # o usa npx
sube new "Inventario simple"
sube deployapp/page.tsx la bodega: stock, sacar, reponer
app/movimientos/page.tsx el libro, append-only
src/db/schema.ts dos tablas: items y movements
middleware.ts y next.config.ts los pone la plataforma. AGENTS.md explica
las reglas que un asistente de IA debe respetar al modificar esta app.
MIT.