chore: remove legacy workspace and restructure API + modular admin UI

This commit is contained in:
mberlin
2026-03-19 09:35:10 -03:00
parent 996c6e9241
commit b60fb432ff
94 changed files with 532 additions and 4086 deletions

View File

@@ -1,15 +0,0 @@
const fs = require('fs');
const path = require('path');
const base = path.resolve(__dirname, '../src/modules');
const mods = ['gifts', 'guests', 'todos'];
for (const mod of mods) {
const folder = path.join(base, mod, 'model');
if (fs.existsSync(folder)) {
try {
fs.rmSync(folder, { recursive: true, force: true });
console.log(`Removed folder ${folder}`);
} catch (err) {
console.warn(`Could not remove ${folder}:`, err.message);
}
}
}

View File

@@ -1,33 +0,0 @@
const fs = require('fs');
const path = require('path');
const base = path.resolve(__dirname, '../src/modules');
const mapping = {
guests: 'guest.model.ts',
gifts: 'gift.model.ts',
todos: 'todo.model.ts',
};
for (const mod of Object.keys(mapping)) {
const modDir = path.join(base, mod);
const modelDir = path.join(modDir, 'model');
const src = path.join(modelDir, mapping[mod]);
const dst = path.join(modDir, 'model.ts');
if (fs.existsSync(src)) {
console.log(`Moving ${src} -> ${dst}`);
fs.renameSync(src, dst);
}
if (fs.existsSync(modelDir)) {
try {
const files = fs.readdirSync(modelDir);
if (files.length === 0) {
console.log(`Removing empty directory ${modelDir}`);
fs.rmdirSync(modelDir);
}
} catch (e) {
console.warn(`Failed to clean model directory ${modelDir}:`, e.message);
}
}
}

View File

@@ -1,8 +0,0 @@
import { z } from "zod";
export const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
});
export type LoginDto = z.infer<typeof loginSchema>;

View File

@@ -1,9 +0,0 @@
import { z } from "zod";
export const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
name: z.string().optional(),
});
export type RegisterDto = z.infer<typeof registerSchema>;

View File

@@ -1,11 +0,0 @@
import { z } from "zod";
export const createContributionSchema = z.object({
giftId: z.string().uuid(),
contributorName: z.string().min(1),
contributorEmail: z.string().email().optional(),
amount: z.number().min(0),
type: z.enum(["individual", "group"]).optional(),
});
export type CreateContributionDto = z.infer<typeof createContributionSchema>;

View File

@@ -1,11 +0,0 @@
import { z } from "zod";
export const createGiftSchema = z.object({
name: z.string().min(1),
description: z.string().optional(),
imageUrl: z.string().optional(),
price: z.number().optional(),
experience: z.boolean().optional(),
});
export type CreateGiftDto = z.infer<typeof createGiftSchema>;

View File

@@ -1,51 +0,0 @@
import { Router } from "express";
import { GiftService } from "../../modules/gifts/service";
import { validateBody } from "../../core/middleware/validate";
import { createGiftSchema, createContributionSchema } from "../../modules/gifts/types";
import { requireAuth } from "../../core/middleware/auth";
const service = new GiftService();
export function registerGiftRoutes(router: Router) {
const r = Router();
// Protected routes
r.use(requireAuth);
r.post("/gift", validateBody(createGiftSchema), async (req, res) => {
const ownerId = (req as any).user?.id;
const gift = await service.createGift({ ...req.body, ownerId });
res.json(gift);
});
r.get("/gift", async (_req, res) => {
const gifts = await service.listGifts();
res.json(gifts);
});
r.get("/gift/:id", async (req, res) => {
const requesterId = (req as any).user?.id;
const gift = await service.getGiftById(req.params.id, requesterId);
if (!gift) {
return res.status(404).json({ error: "Gift not found" });
}
res.json(gift);
});
r.post(
"/gift/contribution",
validateBody(createContributionSchema),
async (req, res) => {
const contribution = await service.createContribution(req.body);
res.json(contribution);
},
);
r.get("/gift/:id/contributions", async (req, res) => {
const requesterId = (req as any).user?.id;
const contributions = await service.listContributions(req.params.id, requesterId);
res.json(contributions);
});
router.use(r);
}

View File

@@ -1,11 +0,0 @@
import { z } from "zod";
export const createGuestSchema = z.object({
name: z.string().min(1),
email: z.string().email().optional(),
phone: z.string().optional(),
rsvp: z.boolean().optional(),
tableId: z.string().uuid().optional(),
});
export type CreateGuestDto = z.infer<typeof createGuestSchema>;

View File

@@ -1,8 +0,0 @@
import { z } from "zod";
export const updateRsvpSchema = z.object({
rsvp: z.boolean(),
tableId: z.string().uuid().optional(),
});
export type UpdateRsvpDto = z.infer<typeof updateRsvpSchema>;

View File

@@ -1,34 +0,0 @@
import { Router } from "express";
import { GuestService } from "../../modules/guests/service";
import { validateBody } from "../../core/middleware/validate";
import { createGuestSchema, updateRsvpSchema } from "../../modules/guests/types";
const service = new GuestService();
export function registerGuestRoutes(router: Router) {
const r = Router();
r.post("/guest", validateBody(createGuestSchema), async (req, res) => {
const guest = await service.createGuest(req.body);
res.json(guest);
});
r.get("/guest", async (_req, res) => {
const guests = await service.listGuests();
res.json(guests);
});
r.patch(
"/guest/:id/rsvp",
validateBody(updateRsvpSchema),
async (req, res) => {
const updated = await service.updateRsvp(req.params.id, req.body);
if (!updated) {
return res.status(404).json({ error: "Guest not found" });
}
res.json(updated);
},
);
router.use(r);
}

View File

@@ -1,7 +0,0 @@
import { Express } from "express";
export function registerHealthRoutes(app: Express) {
app.get("/api/health", (_req, res) => {
res.json({ ok: true, timestamp: new Date().toISOString() });
});
}

View File

@@ -1,18 +1,15 @@
import type { Express } from "express";
import { registerHealthRoutes } from "./health/health.routes";
import { registerAdminRoutes } from "./admin/routes";
import { registerAuthRoutes } from "./auth/routes";
import { registerOrganizadorRoutes } from "./organizador/routes";
import { registerInvitadosRoutes } from "./invitados/routes";
import { registerAuthRoutes } from "./organizador/auth/routes";
import { requireRole, requireInvitadoAccess } from "./middleware";
export function registerApiRoutes(app: Express) {
// shared middleware could be added here (logging, tenant resolution, etc.)
registerHealthRoutes(app);
// Auth routes (register / login) are global and shared by all clients.
app.use("/api/auth", registerAuthRoutes());
// Public auth endpoints for organizer/admin users
app.use("/api/organizador/auth", registerAuthRoutes());
// Admin-only routes
app.use("/api/admin", requireRole("admin"), registerAdminRoutes());

View File

@@ -1,8 +1,8 @@
import { Router } from "express";
import { AuthService } from "../../modules/auth/auth.service";
import { UserService } from "../../modules/auth/user.service";
import { validateBody } from "../../core/middleware/validate";
import { loginSchema, registerSchema } from "../../modules/auth/types";
import { AuthService } from "../../../modules/auth/auth.service";
import { UserService } from "../../../modules/auth/user.service";
import { validateBody } from "../../../core/middleware/validate";
import { loginSchema, registerSchema } from "../../../modules/auth/types";
const authService = new AuthService();
const userService = new UserService();

View File

@@ -0,0 +1,7 @@
import type { Router } from "express";
export function registerHealthRoutes(router: Router) {
router.get("/health", (_req, res) => {
res.json({ ok: true, timestamp: new Date().toISOString() });
});
}

View File

@@ -2,6 +2,7 @@ import { Router } from "express";
import { requireRole } from "../middleware";
import { registerGuestRoutes } from "./guests/routes";
import { registerGiftRoutes } from "./gifts/routes";
import { registerHealthRoutes } from "./health/routes";
import { registerTodoRoutes } from "./todos/routes";
export function registerOrganizadorRoutes() {
@@ -10,6 +11,7 @@ export function registerOrganizadorRoutes() {
// Organizador routes are for organizers (and admins).
// Authentication and role enforcement is handled in api/index.ts.
registerHealthRoutes(router);
registerGuestRoutes(router, requireRole("admin", "organizer"));
registerGiftRoutes(router, requireRole("admin", "organizer"));
registerTodoRoutes(router, requireRole("admin", "organizer"));

View File

@@ -1,9 +0,0 @@
import { z } from "zod";
export const createTodoSchema = z.object({
title: z.string().min(1),
description: z.string().optional(),
dueDate: z.string().optional(),
});
export type CreateTodoDto = z.infer<typeof createTodoSchema>;

View File

@@ -1,33 +0,0 @@
import { Router } from "express";
import { TodoService } from "../../modules/todos/service";
import { validateBody } from "../../core/middleware/validate";
import { createTodoSchema } from "../../modules/todos/types";
import { requireAuth } from "../../core/middleware/auth";
const service = new TodoService();
export function registerTodoRoutes(router: Router) {
const r = Router();
r.use(requireAuth);
r.post("/todo", validateBody(createTodoSchema), async (req, res) => {
const todo = await service.createTodo(req.body);
res.json(todo);
});
r.get("/todo", async (_req, res) => {
const todos = await service.listTodos();
res.json(todos);
});
r.patch("/todo/:id/complete", async (req, res) => {
const updated = await service.markComplete(req.params.id);
if (!updated) {
return res.status(404).json({ error: "Todo not found" });
}
res.json(updated);
});
router.use(r);
}