Expert on GigLedger's database schema, collections, data models, DTOs, caching strategy, and cost control...
This skill provides deep expertise on GigLedger's database design:
Primary Reference: docs/05_data_model_and_schema.md
This document is the authoritative source for all database design decisions.
Reference: docs/05_data_model_and_schema.md section 1
Purpose: User profile and preferences
Schema:
{
"uid": "user123",
"displayName": "User Name",
"email": "user@example.com",
"favorites": {
"[category1]": ["item1", "item2"],
"[category2]": ["itemA"]
},
"preferences": {
"[preference1]": "value",
"[preference2]": true
},
"hasCompletedOnboarding": true,
"createdAt": "timestamp",
"updatedAt": "timestamp"
}
Access: Read/write by authenticated user only (uid must match)
Purpose: [Description]
Schema:
{
"id": "123",
"field1": "value",
"field2": 123,
"metadata": {
"cachedAt": 1234567890,
"status": "completed"
}
}
Access: [Access pattern]
Cache: [Cache duration/strategy]
Characteristics:
lib/features/{feature}/data/dto/Example:
class [Item]DTO {
final String? id;
final String? name;
final Timestamp? createdAt;
[Item]DTO.fromJson(Map<String, dynamic> json)
: id = json['id'],
name = json['name'],
createdAt = json['createdAt'];
[Item] toDomain() {
return [Item](
id: id ?? '',
name: name ?? '',
createdAt: createdAt?.toDate(),
);
}
}
Characteristics:
lib/features/{feature}/domain/models/Example:
class [Item] {
final String id;
final String name;
final DateTime? createdAt;
[Item]({
required this.id,
required this.name,
this.createdAt,
});
// Computed property
bool get isNew => createdAt != null &&
DateTime.now().difference(createdAt!).inDays < 7;
}
Always transform in the data layer:
class [Database][Item]Repository implements [Item]Repository {
@override
Future<[Item]> get[Item](String id) async {
final doc = await database
.collection('[collection]')
.doc(id)
.get();
// Transform DTO → Domain Model
final dto = [Item]DTO.fromJson(doc.data()!);
return dto.toDomain();
}
}
Completed/historical data:
In-progress/live data:
User data:
Enable database persistence for offline support.
Reference: docs/05_data_model_and_schema.md caching section
Critical rules to prevent runaway costs:
Reference: docs/05_data_model_and_schema.md cost control section
Good:
// Limited query with specific fields
final items = await database
.collection('[collection]')
.where('field', isEqualTo: value)
.limit(20)
.get();
Bad:
// Unbounded query
final allItems = await database
.collection('[collection]')
.get(); // Could fetch thousands of documents!
Reference: docs/05_data_model_and_schema.md and docs/12_security_rules.md
User data:
Protected data:
No client-side writes to protected data - Ever.
Future<[Item]> get[Item](String id) async {
final doc = await database
.collection('[collection]')
.doc(id)
.get();
if (!doc.exists) {
throw [Item]NotFoundException(id);
}
final dto = [Item]DTO.fromJson(doc.data()!);
return dto.toDomain();
}
Future<List<[Item]>> getAll[Items](String parentId) async {
final snapshot = await database
.collection('[parent]')
.doc(parentId)
.collection('[items]')
.get();
return snapshot.docs
.map((doc) => [Item]DTO.fromJson(doc.data()).toDomain())
.toList();
}
Future<List<[Item]>> get[Items]ByCategory(String category) async {
final snapshot = await database
.collection('[collection]')
.where('category', isEqualTo: category)
.orderBy('createdAt')
.limit(20)
.get();
return snapshot.docs
.map((doc) => [Item]DTO.fromJson(doc.data()).toDomain())
.toList();
}
Future<[Item]> get[Item](String id) async {
try {
final doc = await database
.collection('[collection]')
.doc(id)
.get();
if (!doc.exists) {
throw [Item]NotFoundException('Item $id not found');
}
final dto = [Item]DTO.fromJson(doc.data()!);
return dto.toDomain();
} on DatabaseException catch (e) {
if (e.code == 'permission-denied') {
throw PermissionDeniedException();
} else if (e.code == 'unavailable') {
throw NetworkException('Database unavailable');
}
rethrow;
}
}
Use this skill when:
When working with database:
docs/05_data_model_and_schema.mddata/dto/ matching database schema exactlydomain/models/ optimized for business logictoDomain() in DTOdata/repository_impl/.limit() on all collection queriesGigLedger's database design ensures:
Remember: Always reference docs/05_data_model_and_schema.md as the ultimate source of truth for database design.