mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 04:19:39 +02:00
- Move finance, mail, moodlit to apps-archived for later development - Rename games/voxel-lava to games/voxelava 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
296 lines
9.8 KiB
Markdown
296 lines
9.8 KiB
Markdown
# Voxel-Lava Datenbank-Dokumentation
|
|
|
|
Diese Dokumentation beschreibt den Aufbau und die Funktionsweise der Supabase-Datenbank für das Voxel-Lava-Spiel. Die Datenbank ermöglicht das Speichern, Teilen und Bewerten von Levels.
|
|
|
|
## Datenbankschema
|
|
|
|
### Tabellen
|
|
|
|
#### 1. `levels`
|
|
|
|
Speichert alle Level-Daten inklusive der Voxel-Informationen.
|
|
|
|
| Spalte | Typ | Beschreibung |
|
|
| --------------- | --------- | ------------------------------------------------------------- |
|
|
| `id` | UUID | Primärschlüssel, automatisch generiert |
|
|
| `name` | TEXT | Name des Levels |
|
|
| `description` | TEXT | Optionale Beschreibung des Levels |
|
|
| `user_id` | UUID | Fremdschlüssel zur `auth.users`-Tabelle, Ersteller des Levels |
|
|
| `voxel_data` | JSONB | Speichert alle Blöcke mit Position und Typ als JSON |
|
|
| `spawn_point` | JSONB | Position des Spawn-Punkts als JSON `{x, y, z}` |
|
|
| `world_size` | JSONB | Größe der Welt als JSON `{width, height, depth}` |
|
|
| `is_public` | BOOLEAN | Gibt an, ob das Level öffentlich ist (Standard: false) |
|
|
| `created_at` | TIMESTAMP | Zeitpunkt der Erstellung |
|
|
| `updated_at` | TIMESTAMP | Zeitpunkt der letzten Aktualisierung |
|
|
| `play_count` | INTEGER | Anzahl der Aufrufe des Levels |
|
|
| `likes_count` | INTEGER | Anzahl der Likes des Levels |
|
|
| `difficulty` | TEXT | Optionaler Schwierigkeitsgrad des Levels |
|
|
| `tags` | TEXT[] | Array von Tags zur Kategorisierung |
|
|
| `thumbnail_url` | TEXT | Optionale URL zum Vorschaubild |
|
|
|
|
#### 2. `level_likes`
|
|
|
|
Speichert die Likes für Levels.
|
|
|
|
| Spalte | Typ | Beschreibung |
|
|
| ------------ | --------- | --------------------------------------- |
|
|
| `id` | UUID | Primärschlüssel, automatisch generiert |
|
|
| `level_id` | UUID | Fremdschlüssel zur `levels`-Tabelle |
|
|
| `user_id` | UUID | Fremdschlüssel zur `auth.users`-Tabelle |
|
|
| `created_at` | TIMESTAMP | Zeitpunkt des Likes |
|
|
|
|
Constraints:
|
|
|
|
- Unique-Constraint auf `(level_id, user_id)`, um doppelte Likes zu verhindern
|
|
|
|
#### 3. `level_plays`
|
|
|
|
Speichert Spielstatistiken für Levels.
|
|
|
|
| Spalte | Typ | Beschreibung |
|
|
| ----------------- | --------- | ------------------------------------------------- |
|
|
| `id` | UUID | Primärschlüssel, automatisch generiert |
|
|
| `level_id` | UUID | Fremdschlüssel zur `levels`-Tabelle |
|
|
| `user_id` | UUID | Fremdschlüssel zur `auth.users`-Tabelle |
|
|
| `completion_time` | FLOAT | Zeit in Sekunden (null, wenn nicht abgeschlossen) |
|
|
| `attempts` | INTEGER | Anzahl der Versuche (Standard: 1) |
|
|
| `completed` | BOOLEAN | Gibt an, ob das Level abgeschlossen wurde |
|
|
| `created_at` | TIMESTAMP | Zeitpunkt des Spielversuchs |
|
|
|
|
### Indizes
|
|
|
|
Zur Optimierung der Abfrageleistung wurden folgende Indizes erstellt:
|
|
|
|
```sql
|
|
CREATE INDEX idx_levels_user_id ON levels(user_id);
|
|
CREATE INDEX idx_levels_is_public ON levels(is_public);
|
|
CREATE INDEX idx_level_likes_level_id ON level_likes(level_id);
|
|
CREATE INDEX idx_level_likes_user_id ON level_likes(user_id);
|
|
CREATE INDEX idx_level_plays_level_id ON level_plays(level_id);
|
|
CREATE INDEX idx_level_plays_user_id ON level_plays(user_id);
|
|
```
|
|
|
|
### Funktionen und Trigger
|
|
|
|
#### 1. `update_updated_at_column()`
|
|
|
|
Aktualisiert automatisch den `updated_at`-Zeitstempel bei Änderungen an einem Level.
|
|
|
|
```sql
|
|
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = now();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER update_levels_updated_at
|
|
BEFORE UPDATE ON levels
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_updated_at_column();
|
|
```
|
|
|
|
#### 2. `update_likes_count()`
|
|
|
|
Aktualisiert automatisch den `likes_count` in der `levels`-Tabelle, wenn ein Like hinzugefügt oder entfernt wird.
|
|
|
|
```sql
|
|
CREATE OR REPLACE FUNCTION update_likes_count()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF TG_OP = 'INSERT' THEN
|
|
UPDATE levels SET likes_count = likes_count + 1 WHERE id = NEW.level_id;
|
|
ELSIF TG_OP = 'DELETE' THEN
|
|
UPDATE levels SET likes_count = likes_count - 1 WHERE id = OLD.level_id;
|
|
END IF;
|
|
RETURN NULL;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER update_level_likes_count
|
|
AFTER INSERT OR DELETE ON level_likes
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_likes_count();
|
|
```
|
|
|
|
#### 3. `update_play_count()`
|
|
|
|
Aktualisiert automatisch den `play_count` in der `levels`-Tabelle, wenn ein Spielversuch hinzugefügt wird.
|
|
|
|
```sql
|
|
CREATE OR REPLACE FUNCTION update_play_count()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF TG_OP = 'INSERT' THEN
|
|
UPDATE levels SET play_count = play_count + 1 WHERE id = NEW.level_id;
|
|
END IF;
|
|
RETURN NULL;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER update_level_play_count
|
|
AFTER INSERT ON level_plays
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_play_count();
|
|
```
|
|
|
|
#### 4. `increment_play_count(level_id UUID)`
|
|
|
|
Erhöht den `play_count` für ein Level, auch wenn kein Benutzer angemeldet ist.
|
|
|
|
```sql
|
|
CREATE OR REPLACE FUNCTION increment_play_count(level_id UUID)
|
|
RETURNS VOID AS $$
|
|
BEGIN
|
|
UPDATE levels SET play_count = play_count + 1 WHERE id = level_id;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
```
|
|
|
|
## Sicherheitsrichtlinien (RLS)
|
|
|
|
Die Datenbank verwendet Row Level Security (RLS), um den Zugriff auf Daten zu kontrollieren:
|
|
|
|
### 1. Levels
|
|
|
|
```sql
|
|
-- Levels sind für Ersteller und öffentlich sichtbar
|
|
CREATE POLICY "Levels sind für Ersteller und öffentlich sichtbar"
|
|
ON levels FOR SELECT
|
|
USING (auth.uid() = user_id OR is_public = true);
|
|
|
|
-- Levels können nur vom Ersteller bearbeitet werden
|
|
CREATE POLICY "Levels können nur vom Ersteller bearbeitet werden"
|
|
ON levels FOR UPDATE
|
|
USING (auth.uid() = user_id);
|
|
|
|
-- Levels können nur vom Ersteller gelöscht werden
|
|
CREATE POLICY "Levels können nur vom Ersteller gelöscht werden"
|
|
ON levels FOR DELETE
|
|
USING (auth.uid() = user_id);
|
|
|
|
-- Neue Levels können nur vom authentifizierten Benutzer erstellt werden
|
|
CREATE POLICY "Neue Levels können nur vom authentifizierten Benutzer erstellt werden"
|
|
ON levels FOR INSERT
|
|
WITH CHECK (auth.uid() = user_id);
|
|
```
|
|
|
|
### 2. Level Likes
|
|
|
|
```sql
|
|
-- Likes können von jedem authentifizierten Benutzer gesehen werden
|
|
CREATE POLICY "Likes können von jedem authentifizierten Benutzer gesehen werden"
|
|
ON level_likes FOR SELECT
|
|
USING (true);
|
|
|
|
-- Likes können nur vom Benutzer selbst erstellt werden
|
|
CREATE POLICY "Likes können nur vom Benutzer selbst erstellt werden"
|
|
ON level_likes FOR INSERT
|
|
WITH CHECK (auth.uid() = user_id);
|
|
|
|
-- Likes können nur vom Benutzer selbst entfernt werden
|
|
CREATE POLICY "Likes können nur vom Benutzer selbst entfernt werden"
|
|
ON level_likes FOR DELETE
|
|
USING (auth.uid() = user_id);
|
|
```
|
|
|
|
### 3. Level Plays
|
|
|
|
```sql
|
|
-- Spielstatistiken sind für Level-Ersteller sichtbar
|
|
CREATE POLICY "Spielstatistiken sind für Level-Ersteller sichtbar"
|
|
ON level_plays FOR SELECT
|
|
USING (EXISTS (
|
|
SELECT 1 FROM levels
|
|
WHERE levels.id = level_plays.level_id
|
|
AND levels.user_id = auth.uid()
|
|
) OR auth.uid() = user_id);
|
|
|
|
-- Spielstatistiken können von jedem authentifizierten Benutzer erstellt werden
|
|
CREATE POLICY "Spielstatistiken können von jedem authentifizierten Benutzer erstellt werden"
|
|
ON level_plays FOR INSERT
|
|
WITH CHECK (auth.uid() = user_id);
|
|
|
|
-- Spielstatistiken können nur vom Benutzer selbst aktualisiert werden
|
|
CREATE POLICY "Spielstatistiken können nur vom Benutzer selbst aktualisiert werden"
|
|
ON level_plays FOR UPDATE
|
|
USING (auth.uid() = user_id);
|
|
```
|
|
|
|
## Datenformat
|
|
|
|
### Voxel-Daten (JSONB)
|
|
|
|
Die Voxel-Daten werden als JSONB in der `voxel_data`-Spalte gespeichert. Das Format ist:
|
|
|
|
```json
|
|
{
|
|
"x,y,z": {
|
|
"type": "blockType",
|
|
"isSpawnPoint": false,
|
|
"isGoal": false
|
|
},
|
|
"1,1,1": {
|
|
"type": "grass",
|
|
"isSpawnPoint": true,
|
|
"isGoal": false
|
|
},
|
|
"5,1,5": {
|
|
"type": "goal",
|
|
"isSpawnPoint": false,
|
|
"isGoal": true
|
|
}
|
|
}
|
|
```
|
|
|
|
Wobei:
|
|
|
|
- Der Schlüssel ist eine Zeichenkette im Format "x,y,z", die die Position des Blocks angibt
|
|
- `type` ist der Typ des Blocks (z.B. "grass", "stone", "lava")
|
|
- `isSpawnPoint` gibt an, ob dieser Block ein Spawn-Punkt ist
|
|
- `isGoal` gibt an, ob dieser Block ein Ziel ist
|
|
|
|
## Verwendung in der Anwendung
|
|
|
|
Die Datenbank wird über den Supabase-Client in der Anwendung angesprochen. Dafür wurden folgende Services implementiert:
|
|
|
|
1. `LevelService`: Zum Speichern, Laden und Verwalten von Levels
|
|
2. `AuthService`: Für die Benutzerauthentifizierung
|
|
|
|
Beispiel für die Verwendung des `LevelService`:
|
|
|
|
```typescript
|
|
import { LevelService } from '../services/LevelService';
|
|
|
|
// Level speichern
|
|
const level = {
|
|
name: 'Mein Level',
|
|
blocks: [
|
|
/* ... */
|
|
],
|
|
spawnPoint: { x: 1, y: 1, z: 1 },
|
|
worldSize: { width: 20, height: 10, depth: 20 },
|
|
isPublic: true,
|
|
};
|
|
const levelId = await LevelService.saveLevel(level);
|
|
|
|
// Level laden
|
|
const loadedLevel = await LevelService.loadLevel(levelId);
|
|
|
|
// Öffentliche Levels abrufen
|
|
const publicLevels = await LevelService.getPublicLevels();
|
|
|
|
// Level liken
|
|
await LevelService.likeLevel(levelId);
|
|
```
|
|
|
|
## Erweiterungsmöglichkeiten
|
|
|
|
Die Datenbankstruktur kann in Zukunft um folgende Funktionen erweitert werden:
|
|
|
|
1. **Kommentare**: Eine neue Tabelle für Kommentare zu Levels
|
|
2. **Leaderboards**: Detaillierte Bestenlisten für jedes Level
|
|
3. **Benutzerprofile**: Erweiterte Benutzerinformationen und Statistiken
|
|
4. **Freundschaften**: Beziehungen zwischen Benutzern
|
|
5. **Sammlungen**: Gruppierung von Levels in Sammlungen oder Playlists
|