Feature batch: Projects, Recurrence, Group settings, Bug fixes

- Projects CRUD API + invite members
- Task recurrence (daily/weekly/monthly) with auto-creation
- Group time zones + GPS locations settings
- i18n fallback fix (no more undefined labels)
- UX: action buttons in one row
- Chat/Calendar: relative API URLs
- DB: task_assignments, projects tables, recurrence column

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 13:49:25 +00:00
parent fc39029ce3
commit b4b8439f80
14 changed files with 1173 additions and 136 deletions

View File

@@ -57,6 +57,50 @@ async function groupRoutes(app) {
}
return { status: 'ok' };
});
// Update time zones for a group
app.put('/groups/:id/timezones', async (req) => {
const { time_zones } = req.body;
if (!Array.isArray(time_zones)) {
throw { statusCode: 400, message: 'time_zones must be an array of [{days, from, to}]' };
}
// Validate each timezone entry
for (const tz of time_zones) {
if (!Array.isArray(tz.days) || !tz.from || !tz.to) {
throw { statusCode: 400, message: 'Each timezone must have days (array), from (HH:MM), to (HH:MM)' };
}
}
const { rows } = await app.db.query(
'UPDATE task_groups SET time_zones = $1, updated_at = NOW() WHERE id = $2 RETURNING *',
[JSON.stringify(time_zones), req.params.id]
);
if (!rows.length) throw { statusCode: 404, message: 'Group not found' };
return { data: rows[0] };
});
// Update GPS locations for a group
app.put('/groups/:id/locations', async (req) => {
const { locations } = req.body;
if (!Array.isArray(locations)) {
throw { statusCode: 400, message: 'locations must be an array of [{name, lat, lng, radius_m}]' };
}
// Validate each location entry
for (const loc of locations) {
if (!loc.name || loc.lat === undefined || loc.lng === undefined) {
throw { statusCode: 400, message: 'Each location must have name, lat, lng' };
}
if (typeof loc.lat !== 'number' || typeof loc.lng !== 'number') {
throw { statusCode: 400, message: 'lat and lng must be numbers' };
}
}
const { rows } = await app.db.query(
'UPDATE task_groups SET locations = $1, updated_at = NOW() WHERE id = $2 RETURNING *',
[JSON.stringify(locations), req.params.id]
);
if (!rows.length) throw { statusCode: 404, message: 'Group not found' };
return { data: rows[0] };
});
}
module.exports = groupRoutes;