feat: implement customizable funnel stages per tenant

- Modified attendances.funnel_stage in DB from ENUM to VARCHAR.

- Created tenant_funnels table and backend API routes to manage custom stages.

- Added /admin/funnels page for Admins/Managers to create, edit, order, and color-code their funnel stages.

- Updated Dashboard, UserDetail, and AttendanceDetail to fetch and render dynamic funnel stages instead of hardcoded enums.

- Added defensive checks and logging to GET /users/:idOrSlug to fix sporadic 500 errors during impersonation handoffs.
This commit is contained in:
Cauê Faleiros
2026-03-13 10:25:23 -03:00
parent 1d49161a05
commit 7ab54053db
18 changed files with 588 additions and 33 deletions

36
debug2.txt Normal file
View File

@@ -0,0 +1,36 @@
Let's see what happens during returnToSuperAdmin:
1. Decode superAdminToken
2. localStorage.setItem('ctms_token', superAdminToken)
3. localStorage.setItem('ctms_user_id', payload.id) <-- u_71657ec7
4. localStorage.setItem('ctms_tenant_id', payload.tenant_id || 'system') <-- 'system'
5. window.location.reload()
Then the app reloads.
1. AuthGuard mounts
2. const storedUserId = localStorage.getItem('ctms_user_id') <-- u_71657ec7
3. const fetchedUser = await getUserById(storedUserId)
-> GET /api/users/u_71657ec7
Backend handles GET /api/users/u_71657ec7:
req.user is derived from jwt.verify(superAdminToken)
So req.user.role === 'super_admin'
req.user.tenant_id === 'system' (or null)
const [rows] = await pool.query('SELECT * FROM users WHERE id = ? OR slug = ?', [req.params.idOrSlug, req.params.idOrSlug]);
if (rows.length === 0) return res.status(404).json({ error: 'Not found' });
if (req.user.role !== 'super_admin' && rows[0].tenant_id !== req.user.tenant_id) { ... }
res.json(rows[0]);
Wait. If this is a 500 error, why does it crash?
What if `req.user` is undefined? But `authenticateToken` middleware ensures `req.user` exists.
Maybe `pool.query` fails?
No, wait. You said:
"now its sending me to login page, congrats"
Then I fixed the Base64 pad.
Then you said:
"i am still having this problem, when i go to impersionate the pages blink and i go to the tenant pages, good, but when i press to go back and stop impersionate it redirects me to the goddam login page"
Then you said:
"ok, its working but its giving some errors in dev tools and this errors is showing our users id and path ... XHRGET https://fasto.blyzer.com.br/api/users/u_71657ec7 [HTTP/2 500 14ms]"
Why 500?
Let's add a console.log in the catch block of `/users/:idOrSlug` to see the actual error.