Web Application Code Review
Code review is not bug hunting, but knowledge transfer and codebase consistency maintenance. Good review reveals architecture issues, potential bugs, convention violations and simplification opportunities.
What We Check in Web App Review
Correctness:
- Logic matches requirements
- Edge cases handled (null, empty arrays, boundary values)
- Error handling present and meaningful
Security:
- Input data validated and sanitized
- SQL-injections excluded (parameterized queries)
- XSS-vulnerabilities absent
- Sensitive data not logged
- Authorization checked on every endpoint
Performance:
- N+1 queries absent
- Heavy operations executed asynchronously
- Correct cache usage
Readability and Maintainability:
- Functions do one thing (Single Responsibility)
- Variable and function names are speaking
- Complex logic has comments
Checklist for React/TypeScript
// BAD: any destroys typing
const handleData = (data: any) => { ... }
// GOOD: explicit type
interface UserData { id: number; name: string; email: string; }
const handleData = (data: UserData) => { ... }
// BAD: useEffect without dependencies (infinite loop)
useEffect(() => {
setData(processData(data));
}); // no dependency array
// BAD: direct state mutation
const handleAdd = () => {
items.push(newItem); // mutation
setItems(items);
};
// GOOD
const handleAdd = () => {
setItems(prev => [...prev, newItem]);
};
// BAD: sensitive data in URL
const url = `/api/users?password=${password}`;
// GOOD: in body
fetch('/api/users', { method: 'POST', body: JSON.stringify({ password }) });
Checklist for API/Backend
// BAD: no input data validation
app.post('/users', async (req, res) => {
const user = await db.user.create({ data: req.body }); // trust client
});
// GOOD: Zod validation
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
role: z.enum(['user', 'editor']), // don't allow 'admin'
});
// BAD: N+1 queries
const posts = await db.post.findMany();
for (const post of posts) {
post.author = await db.user.findUnique({ where: { id: post.authorId } }); // N queries
}
// GOOD: include
const posts = await db.post.findMany({ include: { author: true } });
// BAD: missing permission check
app.delete('/posts/:id', async (req, res) => {
await db.post.delete({ where: { id: req.params.id } }); // anyone can delete anyone's post
});
// GOOD:
app.delete('/posts/:id', authenticate, async (req, res) => {
const post = await db.post.findUnique({ where: { id: req.params.id } });
if (post.authorId !== req.user.id) return res.status(403).json({ error: 'Forbidden' });
await db.post.delete({ where: { id: req.params.id } });
});
Review Process
## Pull Request Template
### What Changed
- Added Google OAuth authorization function
- Fixed bug with double form submission
### How to Test
1. Go to /login
2. Click "Login with Google"
3. Verify session is created
### Checklist
- [ ] Tests written/updated
- [ ] TypeScript without errors (`tsc --noEmit`)
- [ ] Linter without errors (`npm run lint`)
- [ ] Environment variables documented
Automatic Checks
# GitHub Actions: automatic checks before review
- run: npm run typecheck
- run: npm run lint
- run: npm test -- --coverage
- run: npx audit-ci --high
Medium Pull Request review (200–500 lines) — 1–2 hours. Architecture changes review — 4–8 hours.







