feat: first-run web installer with admin account creation
- Backend: app_settings table + users.is_admin flag (schema + migrate)
- POST /api/setup creates admin user, first workspace and marks installed
(transactional, single-use, rate-limited); GET /api/setup/status
- Guard middleware: API answers 503 { setupRequired: true } until installed
- Frontend: /setup wizard (welcome, admin account, workspace), router guard
redirects to installer when uninstalled, API interceptor handles 503
- Docs: installer covered in README, SETUP, HOSTING and ROADMAP
This commit is contained in:
@@ -7,6 +7,7 @@ import morgan from 'morgan';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { pool } from './config/db.js';
|
||||
import authRoutes from './routes/auth.js';
|
||||
import setupRoutes, { isInstalled } from './routes/setup.js';
|
||||
import workspaceRoutes from './routes/workspaces.js';
|
||||
import pageRoutes from './routes/pages.js';
|
||||
import userRoutes from './routes/users.js';
|
||||
@@ -26,6 +27,18 @@ app.use(
|
||||
}),
|
||||
);
|
||||
|
||||
app.use('/api/setup', rateLimit({ windowMs: 15 * 60 * 1000, max: 20 }), setupRoutes);
|
||||
|
||||
// First-run guard: until the web installer completes, every API route
|
||||
// except /api/setup/* and /api/health answers 503 { setupRequired: true }.
|
||||
app.use('/api', async (req, res, next) => {
|
||||
if (req.path === '/health' || req.path.startsWith('/setup')) return next();
|
||||
if (!(await isInstalled())) {
|
||||
return res.status(503).json({ error: 'Initial setup required', setupRequired: true });
|
||||
}
|
||||
return next();
|
||||
});
|
||||
|
||||
app.use('/api/auth', rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }), authRoutes);
|
||||
app.use('/api/workspaces', workspaceRoutes);
|
||||
app.use('/api/pages', pageRoutes);
|
||||
|
||||
Reference in New Issue
Block a user