diff --git a/assets/pasted-20260228-202230-c78e8860.png b/assets/pasted-20260228-202230-c78e8860.png
new file mode 100644
index 0000000..16d229d
Binary files /dev/null and b/assets/pasted-20260228-202230-c78e8860.png differ
diff --git a/assets/pasted-20260302-181039-8b1c369a.png b/assets/pasted-20260302-181039-8b1c369a.png
new file mode 100644
index 0000000..16d229d
Binary files /dev/null and b/assets/pasted-20260302-181039-8b1c369a.png differ
diff --git a/backend/src/db/migrations/20260228100000-grant-public-access.js b/backend/src/db/migrations/20260228100000-grant-public-access.js
new file mode 100644
index 0000000..70b012d
--- /dev/null
+++ b/backend/src/db/migrations/20260228100000-grant-public-access.js
@@ -0,0 +1,44 @@
+
+module.exports = {
+ async up(queryInterface) {
+ const createdAt = new Date();
+ const updatedAt = new Date();
+
+ const [publicRole] = await queryInterface.sequelize.query(
+ "SELECT id FROM roles WHERE name = 'Public' LIMIT 1"
+ );
+
+ if (!publicRole || publicRole.length === 0) {
+ console.error("Public role not found");
+ return;
+ }
+
+ const publicRoleId = publicRole[0].id;
+
+ const [permissions] = await queryInterface.sequelize.query(
+ "SELECT id, name FROM permissions WHERE name IN ('READ_PRODUCTS', 'READ_CATEGORIES', 'CREATE_ORDERS', 'CREATE_ORDER_ITEMS', 'CREATE_PAYMENTS')"
+ );
+
+ const rolePermissions = permissions.map(p => ({
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ roles_permissionsId: publicRoleId,
+ permissionId: p.id
+ })).filter(rp => rp.permissionId);
+
+ if (rolePermissions.length > 0) {
+ // Check if they already exist to avoid duplicates
+ for (const rp of rolePermissions) {
+ const [existing] = await queryInterface.sequelize.query(
+ `SELECT 1 FROM "rolesPermissionsPermissions" WHERE "roles_permissionsId" = '${rp.roles_permissionsId}' AND "permissionId" = '${rp.permissionId}'`
+ );
+ if (existing.length === 0) {
+ await queryInterface.bulkInsert("rolesPermissionsPermissions", [rp]);
+ }
+ }
+ }
+ },
+
+ async down(queryInterface) {
+ }
+};
diff --git a/backend/src/db/seeders/20260228100001-food-store-data.js b/backend/src/db/seeders/20260228100001-food-store-data.js
new file mode 100644
index 0000000..8f2a36e
--- /dev/null
+++ b/backend/src/db/seeders/20260228100001-food-store-data.js
@@ -0,0 +1,86 @@
+
+module.exports = {
+ async up(queryInterface) {
+ const createdAt = new Date();
+ const updatedAt = new Date();
+
+ const [categories] = await queryInterface.bulkInsert('categories', [
+ { id: '10000000-0000-0000-0000-000000000001', name: 'Bebidas', slug: 'bebidas', description: 'Refrescos, jugos y más', createdAt, updatedAt },
+ { id: '10000000-0000-0000-0000-000000000002', name: 'Alimentos Ligeros', slug: 'alimentos-ligeros', description: 'Snacks y comidas rápidas', createdAt, updatedAt },
+ { id: '10000000-0000-0000-0000-000000000003', name: 'Otros', slug: 'otros', description: 'Productos varios', createdAt, updatedAt }
+ ], { returning: true });
+
+ await queryInterface.bulkInsert('products', [
+ {
+ id: '20000000-0000-0000-0000-000000000001',
+ name: 'Coca Cola 500ml',
+ sku: 'BEB-001',
+ slug: 'coca-cola-500ml',
+ short_description: 'Refresco de cola',
+ description: 'Bebida gaseosa refrescante',
+ price: 1.50,
+ stock_quantity: 100,
+ is_active: true,
+ categoryId: '10000000-0000-0000-0000-000000000001',
+ createdAt, updatedAt
+ },
+ {
+ id: '20000000-0000-0000-0000-000000000002',
+ name: 'Jugo de Naranja Natural',
+ sku: 'BEB-002',
+ slug: 'jugo-naranja',
+ short_description: 'Jugo 100% natural',
+ description: 'Exprimido al momento',
+ price: 2.50,
+ stock_quantity: 50,
+ is_active: true,
+ categoryId: '10000000-0000-0000-0000-000000000001',
+ createdAt, updatedAt
+ },
+ {
+ id: '20000000-0000-0000-0000-000000000003',
+ name: 'Sándwich de Jamón y Queso',
+ sku: 'ALM-001',
+ slug: 'sandwich-jamon-queso',
+ short_description: 'Clásico sándwich',
+ description: 'Pan integral, jamón de pavo y queso gouda',
+ price: 3.50,
+ stock_quantity: 30,
+ is_active: true,
+ categoryId: '10000000-0000-0000-0000-000000000002',
+ createdAt, updatedAt
+ },
+ {
+ id: '20000000-0000-0000-0000-000000000004',
+ name: 'Papas Fritas Artesanales',
+ sku: 'ALM-002',
+ slug: 'papas-fritas',
+ short_description: 'Crunchy snacks',
+ description: 'Papas fritas con sal de mar',
+ price: 1.80,
+ stock_quantity: 80,
+ is_active: true,
+ categoryId: '10000000-0000-0000-0000-000000000002',
+ createdAt, updatedAt
+ },
+ {
+ id: '20000000-0000-0000-0000-000000000005',
+ name: 'Café Americano',
+ sku: 'BEB-003',
+ slug: 'cafe-americano',
+ short_description: 'Café caliente',
+ description: 'Granos recién molidos',
+ price: 1.20,
+ stock_quantity: 200,
+ is_active: true,
+ categoryId: '10000000-0000-0000-0000-000000000001',
+ createdAt, updatedAt
+ }
+ ]);
+ },
+
+ async down(queryInterface) {
+ await queryInterface.bulkDelete('products', null, {});
+ await queryInterface.bulkDelete('categories', null, {});
+ }
+};
diff --git a/backend/src/index.js b/backend/src/index.js
index 4808728..67a0932 100644
--- a/backend/src/index.js
+++ b/backend/src/index.js
@@ -1,4 +1,3 @@
-
const express = require('express');
const cors = require('cors');
const app = express();
@@ -111,9 +110,9 @@ app.use('/api/roles', passport.authenticate('jwt', {session: false}), rolesRoute
app.use('/api/permissions', passport.authenticate('jwt', {session: false}), permissionsRoutes);
-app.use('/api/categories', passport.authenticate('jwt', {session: false}), categoriesRoutes);
+app.use('/api/categories', categoriesRoutes);
-app.use('/api/products', passport.authenticate('jwt', {session: false}), productsRoutes);
+app.use('/api/products', productsRoutes);
app.use('/api/addresses', passport.authenticate('jwt', {session: false}), addressesRoutes);
@@ -121,11 +120,11 @@ app.use('/api/carts', passport.authenticate('jwt', {session: false}), cartsRoute
app.use('/api/cart_items', passport.authenticate('jwt', {session: false}), cart_itemsRoutes);
-app.use('/api/orders', passport.authenticate('jwt', {session: false}), ordersRoutes);
+app.use('/api/orders', ordersRoutes);
-app.use('/api/order_items', passport.authenticate('jwt', {session: false}), order_itemsRoutes);
+app.use('/api/order_items', order_itemsRoutes);
-app.use('/api/payments', passport.authenticate('jwt', {session: false}), paymentsRoutes);
+app.use('/api/payments', paymentsRoutes);
app.use('/api/coupons', passport.authenticate('jwt', {session: false}), couponsRoutes);
@@ -175,4 +174,4 @@ db.sequelize.sync().then(function () {
});
});
-module.exports = app;
+module.exports = app;
\ No newline at end of file
diff --git a/frontend/public/logo.png b/frontend/public/logo.png
new file mode 100644
index 0000000..16d229d
Binary files /dev/null and b/frontend/public/logo.png differ
diff --git a/frontend/src/components/AsideMenuLayer.tsx b/frontend/src/components/AsideMenuLayer.tsx
index 50cc1cd..7056ebe 100644
--- a/frontend/src/components/AsideMenuLayer.tsx
+++ b/frontend/src/components/AsideMenuLayer.tsx
@@ -5,6 +5,7 @@ import AsideMenuList from './AsideMenuList'
import { MenuAsideItem } from '../interfaces'
import { useAppSelector } from '../stores/hooks'
import Link from 'next/link';
+import Logo from './Logo';
type Props = {
@@ -37,11 +38,9 @@ export default function AsideMenuLayer({ menu, className = '', ...props }: Props
-
-
-
Tienda Virtual
-
-
+
+
+ Tienda Virtual