mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2026-01-04 03:54:53 +01:00
* Initial plan * Initial plan for repository onboarding instructions Co-authored-by: tankerkiller125 <3457368+tankerkiller125@users.noreply.github.com> * Add comprehensive coding agent instructions for Homebox repository Co-authored-by: tankerkiller125 <3457368+tankerkiller125@users.noreply.github.com> * Optimize instructions to meet 2-page limit while maintaining completeness Co-authored-by: tankerkiller125 <3457368+tankerkiller125@users.noreply.github.com> * Add 4 path-specific instruction files for backend and frontend architecture Co-authored-by: tankerkiller125 <3457368+tankerkiller125@users.noreply.github.com> * Path application for instructions --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: tankerkiller125 <3457368+tankerkiller125@users.noreply.github.com> Co-authored-by: Matt <tankerkiller125@users.noreply.github.com>
7.0 KiB
7.0 KiB
applyTo
| applyTo |
|---|
| backend/internal/data/**/* |
Backend Data Layer Instructions (/backend/internal/data/)
Overview
This directory contains the data access layer using Ent ORM (entity framework). It follows a clear separation between schema definitions, generated code, and repository implementations.
Directory Structure
backend/internal/data/
├── ent/ # Ent ORM generated code (DO NOT EDIT)
│ ├── schema/ # Schema definitions (EDIT THESE)
│ │ ├── item.go # Item entity schema
│ │ ├── user.go # User entity schema
│ │ ├── location.go # Location entity schema
│ │ ├── label.go # Label entity schema
│ │ └── mixins/ # Reusable schema mixins
│ ├── *.go # Generated entity code
│ └── migrate/ # Generated migrations
├── repo/ # Repository pattern implementations
│ ├── repos_all.go # Aggregates all repositories
│ ├── repo_items.go # Item repository
│ ├── repo_users.go # User repository
│ ├── repo_locations.go # Location repository
│ └── *_test.go # Repository tests
├── migrations/ # Manual SQL migrations
│ ├── sqlite3/ # SQLite-specific migrations
│ └── postgres/ # PostgreSQL-specific migrations
└── types/ # Custom data types
Ent ORM Workflow
1. Defining Schemas (ent/schema/)
ALWAYS edit schema files here - these define your database entities:
// Example: backend/internal/data/ent/schema/item.go
type Item struct {
ent.Schema
}
func (Item) Fields() []ent.Field {
return []ent.Field{
field.String("name").NotEmpty(),
field.Int("quantity").Default(1),
field.Bool("archived").Default(false),
}
}
func (Item) Edges() []ent.Edge {
return []ent.Edge{
edge.From("location", Location.Type).Ref("items").Unique(),
edge.From("labels", Label.Type).Ref("items"),
}
}
func (Item) Indexes() []ent.Index {
return []ent.Index{
index.Fields("name"),
index.Fields("archived"),
}
}
Common schema patterns:
- Use
mixins.BaseMixin{}forid,created_at,updated_atfields - Use
mixins.DetailsMixin{}fornameanddescriptionfields - Use
GroupMixin{ref: "items"}to link entities to groups - Add indexes for frequently queried fields
2. Generating Code
After modifying any schema file, ALWAYS run:
task generate
This:
- Runs
go generate ./...inbackend/internal/(generates Ent code) - Generates Swagger docs from API handlers
- Generates TypeScript types for frontend
Generated files you'll see:
ent/*.go- Entity types, builders, queriesent/migrate/migrate.go- Auto migrationsent/predicate/predicate.go- Query predicates
NEVER edit generated files directly - changes will be overwritten.
3. Using Generated Code in Repositories
Repositories in repo/ use the generated Ent client:
// Example: backend/internal/data/repo/repo_items.go
type ItemsRepository struct {
db *ent.Client
bus *eventbus.EventBus
}
func (r *ItemsRepository) Create(ctx context.Context, gid uuid.UUID, data ItemCreate) (ItemOut, error) {
entity, err := r.db.Item.Create().
SetName(data.Name).
SetQuantity(data.Quantity).
SetGroupID(gid).
Save(ctx)
return mapToItemOut(entity), err
}
Repository Pattern
Structure
Each entity typically has:
- Repository struct (
ItemsRepository) - holds DB client and dependencies - Input types (
ItemCreate,ItemUpdate) - API input DTOs - Output types (
ItemOut,ItemSummary) - API response DTOs - Query types (
ItemQuery) - search/filter parameters - Mapper functions (
mapToItemOut) - converts Ent entities to output DTOs
Key Methods
Repositories typically implement:
Create(ctx, gid, input)- Create new entityGet(ctx, id)- Get single entity by IDGetAll(ctx, gid, query)- Query with pagination/filtersUpdate(ctx, id, input)- Update entityDelete(ctx, id)- Delete entity
Working with Ent Queries
Loading relationships (edges):
items, err := r.db.Item.Query().
WithLocation(). // Load location edge
WithLabels(). // Load labels edge
WithChildren(). // Load child items
Where(item.GroupIDEQ(gid)).
All(ctx)
Filtering:
query := r.db.Item.Query().
Where(
item.GroupIDEQ(gid),
item.ArchivedEQ(false),
item.NameContainsFold(search),
)
Ordering and pagination:
items, err := query.
Order(ent.Desc(item.FieldCreatedAt)).
Limit(pageSize).
Offset((page - 1) * pageSize).
All(ctx)
Common Workflows
Adding a New Entity
- Create schema:
backend/internal/data/ent/schema/myentity.go - Run:
task generate(generates Ent code) - Create repository:
backend/internal/data/repo/repo_myentity.go - Add to AllRepos: Edit
repo/repos_all.goto include new repo - Run tests:
task go:test
Adding Fields to Existing Entity
- Edit schema:
backend/internal/data/ent/schema/item.gofield.String("new_field").Optional() - Run:
task generate - Update repository: Add field to input/output types in
repo/repo_items.go - Update mappers: Ensure mapper functions handle new field
- Run tests:
task go:test
Adding Relationships (Edges)
- Edit both schemas:
// In item.go edge.From("location", Location.Type).Ref("items").Unique() // In location.go edge.To("items", Item.Type) - Run:
task generate - Use in queries:
.WithLocation()to load the edge - Run tests:
task go:test
Testing
Repository tests use enttest for in-memory SQLite:
func TestItemRepo(t *testing.T) {
client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&_fk=1")
defer client.Close()
repo := &ItemsRepository{db: client}
// Test methods...
}
Run repository tests:
cd backend && go test ./internal/data/repo -v
Critical Rules
- ALWAYS run
task generateafter schema changes - builds will fail otherwise - NEVER edit files in
ent/exceptent/schema/- they're generated - Use repositories, not raw Ent queries in services/handlers - maintains separation
- Include
group_idin all queries - ensures multi-tenancy - Use
.WithX()to load edges - avoids N+1 queries - Test with both SQLite and PostgreSQL - CI tests both
Common Errors
- "undefined: ent.ItemX" → Run
task generateafter schema changes - Migration conflicts → Check
migrations/for manual migration files - Foreign key violations → Ensure edges are properly defined in both schemas
- Slow queries → Add indexes in schema
Indexes()method