Unify OpenCode and Codex starter kits
- Add .shared/prompts/ with tool-neutral prompts - Add .opencode/config/project.md, rules/, skills/ from opencode-kit - Add .codex/config/project.md from codex-kit - Copy .shared/prompts/ to both .opencode/prompts/ and .codex/prompts/ - Add features/INDEX.md and features/README.md - Update README with unified structure The two original starter kits are now redundant.
This commit is contained in:
@@ -1,20 +1,74 @@
|
||||
# Backend Rules
|
||||
|
||||
## PHP
|
||||
Backend development rules for PHP, databases, and APIs.
|
||||
|
||||
- PHP 8+ Syntax
|
||||
- Prepared Statements für DB Queries
|
||||
- Input Validation immer auf Server-Seite
|
||||
- Keine secrets in Code — .env nutzen
|
||||
## PHP Code
|
||||
|
||||
## REST API
|
||||
- Follow PSR-12 coding standard
|
||||
- Use strict types: `declare(strict_types=1);`
|
||||
- Use typed properties and return types
|
||||
- Maximum function length: ~40 lines
|
||||
- No code duplication — extract to helper functions
|
||||
|
||||
- JSON als Standard-Format
|
||||
- HTTP Status Codes korrekt nutzen
|
||||
- GET/POST/etc. semantisch richtig
|
||||
## API Design
|
||||
|
||||
## SQLite
|
||||
### RESTful Conventions
|
||||
|
||||
- Transactions für mehrere Writes
|
||||
- FOREIGN KEY Constraints aktiviert
|
||||
- Indexes auf häufige Query-Spalten
|
||||
| Method | Path | Action |
|
||||
|--------|------|--------|
|
||||
| GET | /users | List users |
|
||||
| GET | /users/{id} | Get single user |
|
||||
| POST | /users | Create user |
|
||||
| PUT | /users/{id} | Update user |
|
||||
| DELETE | /users/{id} | Delete user |
|
||||
|
||||
### Response Format
|
||||
|
||||
```php
|
||||
// Success
|
||||
json_response(['data' => $user, 'status' => 200]);
|
||||
|
||||
// Error
|
||||
json_response(['error' => 'Not found', 'status' => 404]);
|
||||
|
||||
// List with pagination
|
||||
json_response([
|
||||
'data' => $users,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'per_page' => $perPage
|
||||
]);
|
||||
```
|
||||
|
||||
### Status Codes
|
||||
|
||||
- `200` OK
|
||||
- `201` Created
|
||||
- `204` No Content (successful DELETE)
|
||||
- `400` Bad Request
|
||||
- `401` Unauthorized
|
||||
- `403` Forbidden
|
||||
- `404` Not Found
|
||||
- `422` Unprocessable Entity (validation error)
|
||||
- `500` Internal Server Error
|
||||
|
||||
## Validation
|
||||
|
||||
- Validate in the controller/action before business logic
|
||||
- Return `422` with field-specific errors on validation failure
|
||||
- Never trust user input — validate everything
|
||||
|
||||
## Database
|
||||
|
||||
- Use PDO with parameterized queries (no string interpolation)
|
||||
- Use transactions for multi-step operations
|
||||
- Use indexes on columns used in WHERE/JOIN
|
||||
- Avoid N+1 queries
|
||||
- See `database.md` for SQLite/MariaDB/PostgreSQL portability
|
||||
|
||||
## Testing
|
||||
|
||||
- Unit test business logic in isolation
|
||||
- Integration test API endpoints
|
||||
- Test happy path AND error paths
|
||||
- Mock database in unit tests where practical
|
||||
|
||||
80
.opencode/rules/database.md
Normal file
80
.opencode/rules/database.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Database Rules
|
||||
|
||||
SQLite for development, MariaDB/PostgreSQL for production. Write portable SQL.
|
||||
|
||||
## Development Database
|
||||
|
||||
- Use SQLite for local development (zero-config, no server)
|
||||
- Database file: `database.sqlite` in project root
|
||||
- Create with: `touch database.sqlite`
|
||||
|
||||
## SQL Portability
|
||||
|
||||
### Use Standard SQL Only
|
||||
|
||||
- `CURRENT_TIMESTAMP` — works on SQLite, MariaDB, PostgreSQL
|
||||
- `INTEGER PRIMARY KEY` — portable (mapped to SERIAL/BIGSERIAL)
|
||||
- `TEXT` — portable (avoid VARCHAR length constraints)
|
||||
- `DATETIME` — portable across all three databases
|
||||
|
||||
### Avoid
|
||||
|
||||
| Pattern | Why | Alternative |
|
||||
|---------|-----|-------------|
|
||||
| `REPLACE INTO` | Deletes then inserts (data loss) | `UPDATE ...; INSERT IF 0 rows affected` |
|
||||
| `NOW()` | SQLite/MariaDB specific | `CURRENT_TIMESTAMP` |
|
||||
| `GROUP_CONCAT()` | Not in SQLite | Application-level aggregation |
|
||||
| `IFNULL()` | SQLite syntax | `COALESCE()` (standard) |
|
||||
| Database-specific functions | Locks you in | Do it in application code |
|
||||
|
||||
### Boolean Fields
|
||||
|
||||
SQLite has no BOOLEAN — use INTEGER (0/1):
|
||||
|
||||
```sql
|
||||
CREATE TABLE settings (
|
||||
dark_mode INTEGER DEFAULT 0,
|
||||
notifications INTEGER DEFAULT 1
|
||||
);
|
||||
```
|
||||
|
||||
### String Concatenation
|
||||
|
||||
Do string concatenation in PHP, not SQL.
|
||||
|
||||
### Upsert Pattern
|
||||
|
||||
```php
|
||||
// Safe upsert (works on all databases)
|
||||
$affected = $pdo->prepare(
|
||||
'UPDATE users SET name = ? WHERE id = ?'
|
||||
)->execute([$name, $id]);
|
||||
|
||||
if ($affected === 0) {
|
||||
$pdo->prepare(
|
||||
'INSERT INTO users (id, name) VALUES (?, ?)'
|
||||
)->execute([$id, $name]);
|
||||
}
|
||||
```
|
||||
|
||||
## Migrations
|
||||
|
||||
- Store migrations in `migrations/` directory
|
||||
- Name format: `001_description.sql`, `002_description.sql`
|
||||
- Each migration must be idempotent (use `IF NOT EXISTS`)
|
||||
- Run migrations on every environment
|
||||
|
||||
## Indexes
|
||||
|
||||
- Index columns used in `WHERE`, `JOIN`, `ORDER BY`
|
||||
- Composite indexes: put most selective column first
|
||||
- Don't over-index (write performance cost)
|
||||
|
||||
## No N+1 Queries
|
||||
|
||||
- Use JOINs or batch queries
|
||||
- Eager load relationships when needed
|
||||
|
||||
## Transactions
|
||||
|
||||
Use transactions for any operation that modifies more than one table or row.
|
||||
@@ -1,17 +1,32 @@
|
||||
# Frontend Rules
|
||||
|
||||
## HTML
|
||||
Frontend development rules for React, Next.js, Tailwind CSS, and shadcn/ui.
|
||||
|
||||
- Semantisches HTML5
|
||||
- Accessibility beachten (a11y)
|
||||
## shadcn/ui Components
|
||||
|
||||
## CSS
|
||||
- ALWAYS check `src/components/ui/` first before creating new components
|
||||
- NEVER recreate a component that already exists in shadcn/ui
|
||||
- If missing component: `npx shadcn@latest add <component-name>`
|
||||
|
||||
- CSS Variables für Theming
|
||||
- Mobile-First Ansatz
|
||||
- Keine inline Styles (außer dynamisch)
|
||||
## Styling
|
||||
|
||||
## JS
|
||||
- Use Tailwind CSS utility classes (never raw CSS)
|
||||
- Follow existing patterns in the codebase
|
||||
- Use `clsx` and `tailwind-merge` for conditional classes
|
||||
|
||||
- Vanilla JS bevorzugt, kein Framework-Overhead
|
||||
- ES6+ Syntax
|
||||
## Component Standards
|
||||
|
||||
- All components must be TypeScript (`.tsx`)
|
||||
- Use proper TypeScript types for props
|
||||
- Follow existing component patterns
|
||||
|
||||
## Testing
|
||||
|
||||
- Unit tests co-located next to source files
|
||||
- Pattern: `ComponentName.test.tsx` next to `ComponentName.tsx`
|
||||
- Use `@testing-library/react` for React tests
|
||||
|
||||
## Lint
|
||||
|
||||
- Run `npm run lint` after every change
|
||||
- Fix lint errors before committing
|
||||
@@ -1,20 +1,35 @@
|
||||
# General Rules
|
||||
|
||||
## Projekt Start
|
||||
General development rules for the AI Coding Starter Kit.
|
||||
|
||||
Bei einem neuen Projekt:
|
||||
1. README.md lesen / erstellen
|
||||
2. AGENTS.md lesen
|
||||
3. docs/planung/ öffnen und Projektstruktur verstehen
|
||||
## Feature Tracking
|
||||
|
||||
## Naming
|
||||
- All features MUST be tracked in `features/INDEX.md`
|
||||
- Feature IDs are sequential: PROJ-1, PROJ-2, etc.
|
||||
- Never skip IDs or use non-sequential numbering
|
||||
|
||||
- Kleinbuchstaben mit Bindestrichen: `mein-projekt`
|
||||
- Subdomains als Verzeichnisse unter `www/`
|
||||
- Document-Root immer `public/`
|
||||
## Git Workflow
|
||||
|
||||
## Git Flow
|
||||
- Commits: `feat(PROJ-X): description`, `fix(PROJ-X): description`
|
||||
- Never commit secrets, API keys, or credentials
|
||||
- Always read file before modifying (never assume contents)
|
||||
|
||||
1. Branch für Feature: `feature/<name>`
|
||||
2. Commit oft mit aussagekräftigen Messages
|
||||
3. Merge via PR oder direkt (bei kleinen Fixes)
|
||||
## File Structure
|
||||
|
||||
- Feature specs: `features/PROJ-X-feature-name.md`
|
||||
- Tests: co-located next to source (`*.test.ts` next to `*.ts`)
|
||||
- shadcn/ui components: `src/components/ui/` (NEVER recreate)
|
||||
|
||||
## State Management
|
||||
|
||||
- State lives in files, not in memory
|
||||
- Re-read files when context is compacted
|
||||
- All progress in markdown files (INDEX.md, feature specs)
|
||||
|
||||
## Context Recovery
|
||||
|
||||
If context is compacted:
|
||||
1. Re-read relevant feature spec
|
||||
2. Check `git diff` for uncommitted changes
|
||||
3. Continue from where you left off
|
||||
4. Never restart from scratch without checking progress
|
||||
67
.opencode/rules/php.md
Normal file
67
.opencode/rules/php.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# PHP Rules
|
||||
|
||||
PHP development rules for portable, maintainable code.
|
||||
|
||||
## Code Style
|
||||
|
||||
- Follow PSR-12 coding standard
|
||||
- Use PHP-CS-Fixer or Laravel Pint for formatting
|
||||
- All new files must have `<?php` opening tag (no short tags `<?`)
|
||||
- Use typed properties where possible: `private string $name;`
|
||||
- Use strict types: `declare(strict_types=1);`
|
||||
|
||||
## Naming
|
||||
|
||||
- Classes: `PascalCase`
|
||||
- Methods/functions: `camelCase`
|
||||
- Constants: `SCREAMING_SNAKE_CASE`
|
||||
- Database tables: `snake_case`
|
||||
- Columns: `snake_case`
|
||||
|
||||
## Functions and Methods
|
||||
|
||||
- Maximum function length: ~40 lines
|
||||
- Maximum parameters: ~4 (use DTOs for more)
|
||||
- Never use `extract()` — security risk
|
||||
- Never use `eval()` — security risk
|
||||
- Never use `global` — use dependency injection
|
||||
|
||||
## Type Safety
|
||||
|
||||
- Declare return types on all public methods
|
||||
- Use nullable types intentionally: `?string $name`
|
||||
- Use `void` return type for methods that don't return
|
||||
- Prefer `string` over `String`, `int` over `Integer` (lowercase scalar types)
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Never suppress errors: `@`
|
||||
- Use exceptions for exceptional cases
|
||||
- Catch specific exceptions: `catch (InvalidArgumentException $e)`
|
||||
- Never expose stack traces or internal errors to end users
|
||||
|
||||
## SQL and Database
|
||||
|
||||
- Use parameterized queries exclusively (never string interpolation)
|
||||
- Use transactions for multi-step operations
|
||||
- All SQL must be portable: works on SQLite, MariaDB, PostgreSQL
|
||||
- See `database.md` for full portability rules
|
||||
|
||||
## Composer
|
||||
|
||||
- Run `composer validate` before committing `composer.json`
|
||||
- Lock versions in `composer.lock` (commit it)
|
||||
- No dev dependencies in production deployment
|
||||
|
||||
## Testing
|
||||
|
||||
- PHPUnit or Pest for unit/integration tests
|
||||
- Test one thing per test method
|
||||
- Use data providers for multiple test cases
|
||||
- Mock external dependencies (database, APIs)
|
||||
|
||||
## Files
|
||||
|
||||
- One class per file
|
||||
- File name matches class name: `UserRepository.php` contains `class UserRepository`
|
||||
- No code outside of classes/functions (except config/bootstrap)
|
||||
@@ -1,22 +1,56 @@
|
||||
# Security Rules
|
||||
|
||||
## Generell
|
||||
Security rules for PHP projects.
|
||||
|
||||
- Nie Secrets in Git
|
||||
- Input immer validieren
|
||||
- Output immer escapen
|
||||
## Secrets
|
||||
|
||||
## XSS
|
||||
- NEVER commit secrets, API keys, or credentials
|
||||
- Use `.env` for local development (gitignored via `.gitignore`)
|
||||
- Use environment variables for production
|
||||
- Never log sensitive data (passwords, tokens, personal data)
|
||||
- Generate secrets with: `openssl_random_pseudo_bytes(32)` or `php -r "echo bin2hex(random_bytes(32));"`
|
||||
|
||||
- HTML specialchars() für User-Input in HTML
|
||||
- Content-Security-Policy Header setzen
|
||||
## Input Validation
|
||||
|
||||
## CSRF
|
||||
- Validate ALL user input in PHP (never trust `$_GET`, `$_POST`, etc.)
|
||||
- Use Respect Validation or Laravel Validator
|
||||
- Sanitize data before database insertion
|
||||
- Use parameterized queries exclusively (PDO, mysqli with placeholders)
|
||||
|
||||
- CSRF Token bei Forms
|
||||
- SameSite=Cookie
|
||||
## Output
|
||||
|
||||
## SQL Injection
|
||||
- Escape output with `htmlspecialchars($str, ENT_QUOTES, 'UTF-8')` or framework equivalent
|
||||
- Set Content-Type headers: `Content-Type: text/html; charset=UTF-8`
|
||||
- Use CSRF tokens on all state-changing forms
|
||||
|
||||
- Prepared Statements immer nutzen
|
||||
- Nie User-Input direkt in SQL
|
||||
## Authentication
|
||||
|
||||
- Hash passwords with `password_hash()` (bcrypt/argon2) — NEVER MD5 or SHA1
|
||||
- Use `password_verify()` for comparison
|
||||
- Implement proper session handling: `session_regenerate_id(true)` on login
|
||||
- Set secure cookie flags: `session_set_cookie_params(['httponly' => true, 'secure' => true])`
|
||||
|
||||
## Security Headers
|
||||
|
||||
For production, set these headers:
|
||||
|
||||
```
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Frame-Options: DENY
|
||||
X-XSS-Protection: 1; mode=block
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Content-Security-Policy: default-src 'self'
|
||||
```
|
||||
|
||||
## File Uploads
|
||||
|
||||
- Never trust the filename — generate a new one
|
||||
- Store files outside web root
|
||||
- Validate MIME type server-side (not just by extension)
|
||||
- Set file size limits
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Keep Composer dependencies up to date: `composer outdated`
|
||||
- Run `composer audit` regularly
|
||||
- Update known vulnerable packages immediately
|
||||
Reference in New Issue
Block a user