Aikido

Was wir aus Strapid Codebase gelernt haben: 20 Code-Review-Regeln für skalierbare Entwicklung

Einleitung

Strapi ist eine der beliebtesten Open-Source Headless-CMS-Plattformen, aber auch eine riesige Codebasis mit Hunderten von Mitwirkenden und Tausenden von Pull Requests. Die Qualität eines so großen Projekts hoch zu halten, ist nicht einfach. Es erfordert klare und konsistente Code-Review-Regeln, um sicherzustellen, dass jeder Beitrag zuverlässig, lesbar und sicher bleibt.

In diesem Artikel haben wir eine Reihe von Code-Review-Regeln zusammengestellt, die auf dem öffentlichen Repository von Strapi basieren. Diese Regeln stammen aus der Praxis: tatsächliche Probleme, Diskussionen und Pull Requests, die dem Projekt geholfen haben, zu wachsen und gleichzeitig die Codebasis stabil zu halten.

Warum die Aufrechterhaltung der Codequalität in einem großen Open-Source-Projekt schwierig ist

Die Aufrechterhaltung der Qualität in einem großen Open-Source-Projekt ist aufgrund des schieren Umfangs und der Vielfalt der Beiträge eine Herausforderung. Hunderte oder sogar Tausende von Entwickelnden, von Freiwilligen bis hin zu erfahrenen Ingenieuren, reichen Pull Requests ein, die jeweils neue Funktionen, Fehlerbehebungen oder Refactorings einführen. Ohne klare Regeln kann die Codebasis schnell inkonsistent, brüchig oder schwer zu navigieren werden.

Einige der größten Herausforderungen sind:

  • Vielfältige Mitwirkende mit unterschiedlichen Erfahrungsstufen.
  • Inkonsistente Coding Patterns über Module hinweg.
  • Versteckte Fehler und duplizierte Logik schleichen sich ein.
  • Sicherheitsrisiken, wenn Prozesse nicht durchgesetzt werden.
  • Zeitaufwändige Überprüfungen für Freiwillige, die mit der gesamten Codebasis nicht vertraut sind.

Um diesen Herausforderungen zu begegnen, setzen erfolgreiche Projekte auf strukturierte Prozesse: gemeinsame Standards, automatisierte Tools und klare Richtlinien. Diese Praktiken gewährleisten Wartbarkeit, Lesbarkeit und Sicherheit, selbst wenn das Projekt wächst und mehr Mitwirkende anzieht.

Wie die Einhaltung dieser Regeln Wartbarkeit, Sicherheit und Onboarding verbessert

Die Einhaltung klarer Code-Review-Regeln hat einen direkten Einfluss auf die Integrität Ihres Projekts:

  • Wartbarkeit: Konsistente Ordnerstrukturen, Namenskonventionen und Codierungsmuster erleichtern das Lesen, Navigieren und Erweitern der Codebasis.
  • Sicherheit: Eingabevalidierung, Bereinigung, Berechtigungsprüfungen und kontrollierter Datenbankzugriff reduzieren Schwachstellen und verhindern unbeabsichtigte Datenlecks.
  • Schnelleres Onboarding: Gemeinsame Standards, dokumentierte Dienstprogramme und klare Beispiele helfen neuen Mitwirkenden, das Projekt schnell zu verstehen und selbstbewusst beizutragen.

Durch die Anwendung dieser Regeln können Teams sicherstellen, dass die Codebasis skalierbar, zuverlässig und sicher bleibt, selbst wenn die Anzahl der Mitwirkenden wächst.

Kontext mit Regeln verknüpfen

Bevor wir uns die Regeln ansehen, ist es wichtig zu verstehen, dass die Aufrechterhaltung einer hohen Codequalität in einem Projekt wie Strapi nicht nur das Befolgen allgemeiner Best Practices bedeutet. Es geht darum, klare Muster und Standards zu haben, die Hunderten von Mitwirkenden helfen, auf dem gleichen Stand zu bleiben. Jede der 20 Regeln unten konzentriert sich auf reale Herausforderungen, die in der Codebasis von Strapi auftreten.

Die für jede Regel bereitgestellten Beispiele veranschaulichen sowohl nicht-konforme als auch konforme Ansätze und vermitteln ein klares Bild davon, wie diese Prinzipien in der Praxis angewendet werden.

Lassen Sie uns nun die Regeln erkunden, die die Codebasis von Strapi skalierbar, konsistent und hochwertig machen, beginnend mit Projektstruktur und Konfigurationsstandards.

Regeln: Projektstruktur & Konsistenz

1. Befolgen Sie Strapis etablierte Ordnerkonventionen

Vermeiden Sie es, Dateien zu verstreuen oder neue Strukturen zu erfinden. Halten Sie sich an das etablierte Projektlayout von Strapi, um die Navigation vorhersehbar zu halten.

Nicht konformes Beispiel

1src/
2├── controllers/
3│   └── userController.js
4├── services/
5│   └── userLogic.js
6├── routes/
7│   └── userRoutes.js
8└── utils/
9    └── helper.js

Compliance-konformes Beispiel

1src/
2└── api/
3    └── user/
4        ├── controllers/
5        │   └── user.js
6        ├── services/
7        │   └── user.js
8        ├── routes/
9        │   └── user.js
10        └── content-types/
11            └── user/schema.json

2. Konfigurationsdateien konsistent halten

Verwenden Sie in allen Konfigurationsdateien dieselben Struktur-, Benennungs- und Formatierungskonventionen, um Konsistenz zu gewährleisten und Fehler zu vermeiden.

Nicht konformes Beispiel

1// config/server.js
2module.exports = {
3    PORT: 1337,
4    host: '0.0.0.0',
5    APP_NAME: 'my-app'
6}
7
8// config/database.js
9export default {
10  connection: {
11    client: 'sqlite',
12    connection: { filename: '.tmp/data.db' }
13  }
14}
15
16// config/plugins.js
17module.exports = ({ env }) => ({
18   upload: { provider: "local" },
19   email: { provider: 'sendgrid' }
20});

Compliance-konformes Beispiel

1// config/server.js
2module.exports = ({ env }) => ({
3  host: env('HOST', '0.0.0.0'),
4  port: env.int('PORT', 1337),
5  app: { keys: env.array('APP_KEYS') },
6});
7
8// config/database.js
9module.exports = ({ env }) => ({
10  connection: {
11    client: 'sqlite',
12    connection: { filename: env('DATABASE_FILENAME', '.tmp/data.db') },
13    useNullAsDefault: true,
14  },
15});
16
17// config/plugins.js
18module.exports = ({ env }) => ({
19  upload: { provider: 'local' },
20  email: { provider: 'sendgrid' },
21});

3. Strikte Typsicherheit gewährleisten

Sämtlicher neuer oder aktualisierter Code muss genaue TypeScript-Typen oder JSDoc-Definitionen enthalten. Vermeiden Sie die Verwendung von 'any', fehlende Rückgabetypen oder implizite Typinferenz in gemeinsam genutzten Modulen.

Nicht konformes Beispiel

1// src/api/user/services/user.ts
2export const createUser = (data) => {
3  return strapi.db.query('api::user.user').create({ data });
4};

Compliance-konformes Beispiel

1// src/api/user/services/user.ts
2import { User } from './types';
3
4export const createUser = async (data: User): Promise<User> => {
5  return await strapi.db.query('api::user.user').create({ data });
6};

4. Konsistente Benennung von Services und Controllern

Controller- und Dienstnamen müssen eindeutig ihrer Domäne entsprechen (z. B. user.controller.js mit user.service.js).

Nicht konformes Beispiel

1src/
2└── api/
3    └── user/
4        ├── controllers/
5        │   └── mainController.js
6        ├── services/
7        │   └── accountService.js
8        ├── routes/
9        │   └── user.js

Compliance-konformes Beispiel

1src/
2└── api/
3    └── user/
4        ├── controllers/
5        │   └── user.js
6        ├── services/
7        │   └── user.js
8        ├── routes/
9        │   └── user.js
10        └── content-types/
11            └── user/schema.json

Regeln: Code-Qualität & Wartbarkeit

5. Kontrollfluss mit Early Returns vereinfachen

Anstatt tiefer if/else-Verschachtelungen frühzeitig zurückkehren, wenn Bedingungen fehlschlagen.

Nicht konformes Beispiel

1// src/api/article/controllers/article.js
2module.exports = {
3  async create(ctx) {
4    const { title, content, author } = ctx.request.body;
5
6    if (title) {
7      if (content) {
8        if (author) {
9          const article = await strapi.db.query('api::article.article').create({
10            data: { title, content, author },
11          });
12          ctx.body = article;
13        } else {
14          ctx.throw(400, 'Missing author');
15        }
16      } else {
17        ctx.throw(400, 'Missing content');
18      }
19    } else {
20      ctx.throw(400, 'Missing title');
21    }
22  },
23};

Compliance-konformes Beispiel

1// src/api/article/controllers/article.js
2module.exports = {
3  async create(ctx) {
4    const { title, content, author } = ctx.request.body;
5
6    if (!title) ctx.throw(400, 'Missing title');
7    if (!content) ctx.throw(400, 'Missing content');
8    if (!author) ctx.throw(400, 'Missing author');
9
10    const article = await strapi.db.query('api::article.article').create({
11      data: { title, content, author },
12    });
13
14    ctx.body = article;
15  },
16};

6. Vermeiden Sie übermäßige Verschachtelung in Controllern

Große Blöcke verschachtelter Logik in Controllern oder Services vermeiden. Wiederholte oder komplexe Bedingungen in gut benannte Hilfsfunktionen oder Utilities auslagern.

Nicht konformes Beispiel

1// src/api/order/controllers/order.js
2module.exports = {
3  async create(ctx) {
4    const { items, user } = ctx.request.body;
5
6    if (user && user.role === 'customer') {
7      if (items && items.length > 0) {
8        const stock = await strapi.service('api::inventory.inventory').checkStock(items);
9        if (stock.every((i) => i.available)) {
10          const order = await strapi.db.query('api::order.order').create({ data: { items, user } });
11          ctx.body = order;
12        } else {
13          ctx.throw(400, 'Some items are out of stock');
14        }
15      } else {
16        ctx.throw(400, 'No items in order');
17      }
18    } else {
19      ctx.throw(403, 'Unauthorized user');
20    }
21  },
22};

Compliance-konformes Beispiel

1// src/api/order/utils/validation.js
2const isCustomer = (user) => user?.role === 'customer';
3const hasItems = (items) => Array.isArray(items) && items.length > 0;
4
5// src/api/order/controllers/order.js
6module.exports = {
7  async create(ctx) {
8    const { items, user } = ctx.request.body;
9
10    if (!isCustomer(user)) ctx.throw(403, 'Unauthorized user');
11    if (!hasItems(items)) ctx.throw(400, 'No items in order');
12
13    const stock = await strapi.service('api::inventory.inventory').checkStock(items);
14    const allAvailable = stock.every((i) => i.available);
15    if (!allAvailable) ctx.throw(400, 'Some items are out of stock');
16
17    const order = await strapi.db.query('api::order.order').create({ data: { items, user } });
18    ctx.body = order;
19  },
20};

7. Geschäftslogik aus Controllern heraushalten

Controller sollten schlank bleiben und nur Anfragen orchestrieren. Verschieben Sie die Geschäftslogik in Services.

Nicht konformes Beispiel

1// src/api/article/controllers/article.js
2module.exports = {
3  async create(ctx) {
4    const { title, content, authorId } = ctx.request.body;
5
6    const author = await strapi.db.query('api::author.author').findOne({ where: { id: authorId } });
7    if (!author) ctx.throw(400, 'Author not found');
8
9    const timestamp = new Date().toISOString();
10    const slug = title.toLowerCase().replace(/\s+/g, '-');
11
12    const article = await strapi.db.query('api::article.article').create({
13      data: { title, content, slug, publishedAt: timestamp, author },
14    });
15
16    await strapi.plugins['email'].services.email.send({
17      to: author.email,
18      subject: `New article: ${title}`,
19      html: `<p>${content}</p>`,
20    });
21
22    ctx.body = article;
23  },
24};

Compliance-konformes Beispiel

1// src/api/article/controllers/article.js
2module.exports = {
3  async create(ctx) {
4    const article = await strapi.service('api::article.article').createArticle(ctx.request.body);
5    ctx.body = article;
6  },
7};
// src/api/article/services/article.js
module.exports = ({ strapi }) => ({
  async createArticle(data) {
    const { title, content, authorId } = data;

    const author = await strapi.db.query('api::author.author').findOne({ where: { id: authorId } });
    if (!author) throw new Error('Author not found');

    const slug = title.toLowerCase().replace(/\s+/g, '-');
    const article = await strapi.db.query('api::article.article').create({
      data: { title, content, slug, author },
    });

    await strapi.plugins['email'].services.email.send({
      to: author.email,
      subject: `New article: ${title}`,
      html: `<p>${content}</p>`,
    });

    return article;
  },
});

8. Nutzung von Utility-Funktionen für wiederkehrende Muster

Doppelte Muster (z. B. Validierung, Formatierung) sollten in gemeinsamen Dienstprogrammen untergebracht werden.

Nicht konformes Beispiel

// src/api/article/controllers/article.js
module.exports = {
  async create(ctx) {
    const { title } = ctx.request.body;
    const slug = title.toLowerCase().replace(/\s+/g, '-');
    ctx.body = await strapi.db.query('api::article.article').create({ data: { ...ctx.request.body, slug } });
  },
};

// src/api/event/controllers/event.js
module.exports = {
  async create(ctx) {
    const { name } = ctx.request.body;
    const slug = name.toLowerCase().replace(/\s+/g, '-');
    ctx.body = await strapi.db.query('api::event.event').create({ data: { ...ctx.request.body, slug } });
  },
};

Compliance-konformes Beispiel

// src/utils/slugify.js
module.exports = (text) => text.toLowerCase().trim().replace(/\s+/g, '-');
// src/api/article/controllers/article.js
const slugify = require('../../../utils/slugify');

module.exports = {
  async create(ctx) {
    const { title } = ctx.request.body;
    const slug = slugify(title);
    ctx.body = await strapi.db.query('api::article.article').create({ data: { ...ctx.request.body, slug } });
  },
};

9. Debugging-Logs vor der Produktion entfernen

Verwenden Sie keine console.log, console.warn oder console.error im Produktionscode. Verwenden Sie immer strapi.log oder einen konfigurierten Logger, um sicherzustellen, dass Logs Umgebungseinstellungen respektieren und die Offenlegung sensibler Informationen vermieden wird.

Nicht konformes Beispiel

// src/api/user/controllers/user.js
module.exports = {
  async find(ctx) {
    console.log('Request received:', ctx.request.body); // Unsafe in production
    const users = await strapi.db.query('api::user.user').findMany();
    console.log('Users fetched:', users.length);
    ctx.body = users;
  },
};

Compliance-konformes Beispiel

// src/api/user/controllers/user.js
module.exports = {
  async find(ctx) {
    strapi.log.info(`Fetching users for request from ${ctx.state.user?.email || 'anonymous'}`);
    const users = await strapi.db.query('api::user.user').findMany();
    strapi.log.debug(`Number of users fetched: ${users.length}`);
    ctx.body = users;
  },
};
if (process.env.NODE_ENV === 'development') {
  strapi.log.debug('Request body:', ctx.request.body);
}

Regeln: Datenbank- & Abfragepraktiken

10. Rohe SQL-Abfragen vermeiden

Führen Sie keine rohen SQL-Abfragen in Controllern oder Diensten aus. Verwenden Sie immer eine konsistente, übergeordnete Abfragemethode (wie ein ORM oder Query Builder), um die Wartbarkeit zu gewährleisten, Regeln/Hooks durchzusetzen und Sicherheitsrisiken zu reduzieren.

Nicht konformes Beispiel

// src/api/user/services/user.js
module.exports = {
  async findActiveUsers() {
    const knex = strapi.db.connection; 
    const result = await knex.raw('SELECT * FROM users WHERE active = true'); // Raw SQL
    return result.rows;
  },
};

Compliance-konformes Beispiel

// src/api/user/services/user.js
module.exports = {
  async findActiveUsers() {
    return await strapi.db.query('api::user.user').findMany({
      where: { active: true },
    });
  },
};

11. Strapis Query Engine konsistent verwenden

Mischen Sie keine verschiedenen Datenbankzugriffsmethoden (z. B. ORM-Aufrufe vs. rohe Abfragen) innerhalb desselben Features. Verwenden Sie einen einzigen, konsistenten Abfrageansatz, um Wartbarkeit, Lesbarkeit und vorhersehbares Verhalten zu gewährleisten.

Nicht konformes Beispiel

// src/api/order/services/order.js
module.exports = {
  async getPendingOrders() {
    // Using entityService
    const orders = await strapi.entityService.findMany('api::order.order', {
      filters: { status: 'pending' },
    });

    // Mixing with raw db query
    const rawOrders = await strapi.db.connection.raw('SELECT * FROM orders WHERE status = "pending"');

    return { orders, rawOrders };
  },
};

Compliance-konformes Beispiel

// src/api/order/services/order.js
module.exports = {
  async getPendingOrders() {
    return await strapi.db.query('api::order.order').findMany({
      where: { status: 'pending' },
    });
  },
};

12. Datenbankaufrufe optimieren

Zugehörige Datenbankabfragen bündeln oder zu einem einzigen Vorgang zusammenfassen, um Performance-Engpässe zu vermeiden und unnötige sequentielle Aufrufe zu reduzieren.

Nicht konformes Beispiel

async function getArticlesWithAuthors() {
  const articles = await db.query('articles').findMany();

  // Fetch author for each article sequentially
  for (const article of articles) {
    article.author = await db.query('authors').findOne({ id: article.authorId });
  }

  return articles;
}

Compliance-konformes Beispiel

async function getArticlesWithAuthors() {
  return await db.query('articles').findMany({ populate: ['author'] });
}

Regeln: API & Security

13. Eingaben mit Strapi-Validatoren validieren

Vertrauen Sie niemals Eingaben von Clients oder externen Quellen.Validieren Sie alle eingehenden Daten mit einem konsistenten Validierungsmechanismus, bevor Sie sie in Controllern, Services oder Datenbankoperationen verwenden.

Nicht konformes Beispiel

async function createUser(req, res) {
  const { username, email } = req.body;

  // Directly inserting into database without validation
  const user = await db.query('users').create({ username, email });
  res.send(user);
}

Compliance-konformes Beispiel

const Joi = require('joi');

async function createUser(req, res) {
  const schema = Joi.object({
    username: Joi.string().min(3).required(),
    email: Joi.string().email().required(),
  });

  const { error, value } = schema.validate(req.body);
  if (error) return res.status(400).send(error.details);

  const user = await db.query('users').create(value);
  res.send(user);
}

14. Benutzereingaben vor dem Speichern bereinigen

Bereinigen Sie alle Eingaben, bevor Sie sie in der Datenbank speichern oder an andere Systeme weitergeben.

Nicht konformes Beispiel

async function createComment(req, res) {
  const { text, postId } = req.body;

  // Directly saving data
  const comment = await db.query('comments').create({ text, postId });
  res.send(comment);
}

Compliance-konformes Beispiel

const sanitizeHtml = require('sanitize-html');

async function createComment(req, res) {
  const { text, postId } = req.body;

  const sanitizedText = sanitizeHtml(text, { allowedTags: [], allowedAttributes: {} });

  const comment = await db.query('comments').create({ text: sanitizedText, postId });
  res.send(comment);
}

15. Berechtigungsprüfungen erzwingen

Wenden Sie Berechtigungsprüfungen auf jeder geschützten Route an, um sicherzustellen, dass nur autorisierte Benutzer darauf zugreifen können.

Nicht konformes Beispiel

async function deleteUser(req, res) {
  const { userId } = req.params;

  // No check for admin or owner
  await db.query('users').delete({ id: userId });
  res.send({ success: true });
}

Compliance-konformes Beispiel

async function deleteUser(req, res) {
  const { userId } = req.params;
  const requestingUser = req.user;

  // Allow only admins or the owner
  if (!requestingUser.isAdmin && requestingUser.id !== userId) {
    return res.status(403).send({ error: 'Forbidden' });
  }

  await db.query('users').delete({ id: userId });
  res.send({ success: true });
}

16. Konsistente Fehlerbehandlung mit Boom

Fehler konsistent über alle API-Routen hinweg behandeln, mithilfe eines zentralisierten oder vereinheitlichten Fehlerbehandlungsmechanismus.

Nicht konformes Beispiel

async function getUser(req, res) {
  const { id } = req.params;

  try {
    const user = await db.query('users').findOne({ id });
    if (!user) res.status(404).send('User not found'); // raw string error
    else res.send(user);
  } catch (err) {
    res.status(500).send(err.message); // different error format
  }
}

Compliance-konformes Beispiel

const { createError } = require('../utils/errors');

async function getUser(req, res, next) {
  try {
    const { id } = req.params;
    const user = await db.query('users').findOne({ id });

    if (!user) throw createError(404, 'User not found');

    res.send(user);
  } catch (err) {
    next(err); // passes error to centralized error handler
  }
}
// src/utils/errors.js
function createError(status, message) {
  return { status, message };
}

function errorHandler(err, req, res, next) {
  res.status(err.status || 500).json({ error: err.message });
}

module.exports = { createError, errorHandler };

Regeln: Testen & Dokumentation

17. Tests für jede Funktion hinzufügen oder aktualisieren

Neuer Code ohne Tests wird nicht gemergt, Tests sind Teil der Definition von Done.

Nicht konformes Beispiel

// src/api/user/services/user.js
module.exports = {
  async createUser(data) {
    const user = await db.query('users').create(data);
    return user;
  },
};

// No test file exists for this service

Compliance-konformes Beispiel

// tests/user.service.test.js
const { createUser } = require('../../src/api/user/services/user');

describe('User Service', () => {
  it('should create a new user', async () => {
    const mockData = { username: 'testuser', email: 'test@example.com' };
    const result = await createUser(mockData);

    expect(result).toHaveProperty('id');
    expect(result.username).toBe('testuser');
    expect(result.email).toBe('test@example.com');
  });
});

18. Neue Endpunkte dokumentieren

Jede API-Ergänzung muss vor dem Merge in den Referenzdokumenten dokumentiert werden.

Nicht konformes Beispiel

// src/api/user/controllers/user.js
module.exports = {
  async deactivate(ctx) {
    const { userId } = ctx.request.body;
    await db.query('users').update({ id: userId, active: false });
    ctx.body = { success: true };
  },
};

// No update in API reference or docs

Compliance-konformes Beispiel

// src/api/user/controllers/user.js
module.exports = {
  /**
   * Deactivate a user account.
   * POST /users/deactivate
   * Body: { userId: string }
   * Response: { success: boolean }
   * Errors: 400 if userId missing, 404 if user not found
   */
  async deactivate(ctx) {
    const { userId } = ctx.request.body;
    if (!userId) ctx.throw(400, 'userId is required');

    const user = await db.query('users').findOne({ id: userId });
    if (!user) ctx.throw(404, 'User not found');

    await db.query('users').update({ id: userId, active: false });
    ctx.body = { success: true };
  },
};

Beispiel für die Aktualisierung der Referenzdokumentation:

### POST /users/deactivate

**Request Body:**
```json
{
  "userId": "string"
}

Reaktion:

{
  "success": true
}

Fehler:

  • 400: userId ist erforderlich
  • 404: Benutzer nicht gefunden
Warum das funktioniert: 
- Entwickelnde und API-Konsumenten können Endpunkte zuverlässig entdecken und nutzen 
- Stellt Konsistenz zwischen Implementierung und Dokumentation sicher 
- Erleichtert Wartung und Onboarding 

---

Möchten Sie, dass ich mit **Regel #19 („JSDoc für Shared Utilities verwenden“)** im gleichen Format fortfahre?

19. JSDoc für gemeinsam genutzte Dienstprogramme verwenden

Geteilte Funktionen sollten mit JSDoc erklärt werden, um Onboarding und Zusammenarbeit zu erleichtern.

Nicht konformes Beispiel

// src/utils/slugify.js
function slugify(text) {
  return text.toLowerCase().trim().replace(/\s+/g, '-');
}

module.exports = slugify;

Compliance-konformes Beispiel

// src/utils/slugify.js

/**
 * Converts a string into a URL-friendly slug.
 *
 * @param {string} text - The input string to convert.
 * @returns {string} A lowercased, trimmed, dash-separated slug.
 */
function slugify(text) {
  return text.toLowerCase().trim().replace(/\s+/g, '-');
}

module.exports = slugify;

20. Changelog mit jedem signifikanten PR aktualisieren

Aktualisieren Sie das Changelog des Projekts mit jeder wesentlichen Funktion, jedem Bugfix oder jeder API-Änderung, bevor Sie einen PR mergen.

Nicht konformes Beispiel

# CHANGELOG.md

## [1.0.0] - 2025-09-01
- Erstveröffentlichung

Compliance-konformes Beispiel

# CHANGELOG.md

## [1.1.0] - 2025-10-06
- Endpunkt zur Benutzerdeaktivierung hinzugefügt (`POST /users/deactivate`)
- Fehler bei der Slug-Generierung für Artikeltitel behoben
- E-Mail-Benachrichtigungsdienst für den Stapelversand aktualisiert

Fazit

Wir haben Strapi’s öffentliches Repository untersucht, um zu verstehen, wie konsistente Code-Muster großen Open-Source-Projekten helfen, ohne Qualitätsverlust zu wachsen. Diese 20 Regeln sind keine Theorie. Es sind praktische Lektionen, die direkt aus Strapi’s Codebasis stammen und das Projekt wartbarer, sicherer und lesbarer machen.

Wenn Ihr Projekt wächst, übernehmen Sie diese Lektionen und wenden Sie sie auf Ihre Code-Reviews an. Sie helfen Ihnen, weniger Zeit mit dem Aufräumen von unordentlichem Code zu verbringen und mehr Zeit mit dem Erstellen von Features, die wirklich wichtig sind.

FAQs

Haben Sie Fragen?

Warum sind Code-Review-Regeln in Open-Source-Projekten wie Strapi wichtig?

Da Hunderte von Entwickelnden beitragen, verhindern konsistente Überprüfungsregeln Chaos. Sie stellen sicher, dass jeder Pull Request dieselben Struktur-, Benennungs- und Sicherheitsmuster befolgt, was das Projekt über die Zeit stabil und wartbar hält.

Wie hält Strapi die Code-Qualität im großen Maßstab aufrecht?

Strapi verwendet strenge Ordnerkonventionen, TypeScript-Einführung, automatisierte Tests und standardisierte Validierung. Jede Änderung wird vor dem Mergen auf Klarheit, Leistung und Sicherheit überprüft.

Was ist der Unterschied zwischen Linting und Code-Review-Regeln?

Linting erkennt Syntax- und Formatierungsfehler automatisch. Code-Review-Regeln gehen tiefer – sie behandeln Architektur, Lesbarkeit, Namensklarheit, Wartbarkeit und Sicherheit, die Tools ohne menschlichen oder KI-basierten Kontext nicht erkennen können.

Wie können Teams diese Regeln auf ihre eigenen Projekte anwenden?

- Dokumentieren Sie Ihre Review-Standards.
- Fügen Sie automatisierte Prüfungen und PR-Vorlagen hinzu.
- Verwenden Sie konsistente Benennungen und Ordnerstrukturen.
- Erzwingen Sie Tests und Dokumentations-Updates bei jedem Merge.
- Führen Sie KI-basierte Code-Review-Tools wie Aikido Code Quality aus, um übergeordnete Designprobleme zu erkennen.

Welche Tools können dabei helfen, Code-Review-Regeln automatisch durchzusetzen?

Tools wie Aikido Security Code Quality helfen, Architektur-, Wartbarkeits- und Sicherheitsprobleme während Code-Reviews zu erkennen – und gehen dabei weit über traditionelles Linting hinaus.

Was ist die größte Herausforderung bei der Pflege der Strapi-Codebasis?

Innovation und Konsistenz ausbalancieren – neue Mitwirkende bringen frische Ideen ein, doch ohne klare Regeln läuft das Projekt Gefahr, in inkonsistente Muster und schwer wartbaren Code abzugleiten.

Wie verbessern diese Regeln das Onboarding für neue Mitwirkende?

Sie bieten eine klare Roadmap der Erwartungen. Wenn Ordnerstruktur, Benennung und Dokumentation vorhersehbar sind, können neue Entwickelnde schnell verstehen, wie sie beitragen können, ohne bestehende Muster zu durchbrechen.

Sicherheit jetzt implementieren

Sichern Sie Ihren Code, Ihre Cloud und Ihre Laufzeit in einem zentralen System.
Finden und beheben Sie Schwachstellen schnell und automatisch.

Keine Kreditkarte erforderlich | Scan-Ergebnisse in 32 Sek.