Skip to content

Development Guide

Project Style

Eco Manager is a contract-driven modular monolith.

The codebase should be easy for one or two developers to understand, maintain, and extend.

Prefer simple vertical slices over abstract enterprise layering.

Workspace Structure

text
.
├── apps/
│   ├── backend/
│   ├── frontend/
│   └── admin/

├── packages/
│   ├── contracts/
│   ├── db/
│   ├── auth/
│   ├── permissions/
│   └── shared/

└── docs/

App Responsibilities

apps/backend

Owns API routes, services, transactions, authorization checks, audit events, Vault operations, and integrations.

apps/frontend

Owns the normal engineer and operations user experience.

apps/admin

Owns Admin Studio: the super-user CRUD/configuration interface for the Universal Entity Platform.

Admin Studio should not bypass the backend. It uses contracts and API calls like any other frontend app.

Suggested Backend Module Structure

text
apps/backend/src/modules/

├── entities/
│   ├── entities.routes.ts
│   ├── entities.service.ts
│   ├── entities.permissions.ts
│   ├── entities.validators.ts
│   │
│   ├── use-cases/
│   │   ├── create-entity.ts
│   │   ├── update-entity.ts
│   │   ├── move-entity.ts
│   │   ├── soft-delete-entity.ts
│   │   ├── restore-entity.ts
│   │   └── purge-entity.ts
│   │
│   ├── hierarchy/
│   │   ├── get-children.ts
│   │   ├── get-descendants.ts
│   │   ├── get-ancestors.ts
│   │   ├── get-path.ts
│   │   └── validate-reparent.ts
│   │
│   ├── groups/
│   ├── properties/
│   ├── tags/
│   └── relationships/

├── admin/
│   ├── admin.routes.ts
│   ├── admin.permissions.ts
│   └── use-cases/
│       ├── preview-bulk-operation.ts
│       ├── perform-bulk-operation.ts
│       ├── inspect-entity-config.ts
│       └── restore-deleted-record.ts

├── vault/
├── assets/
├── customers/
├── sites/
├── buildings/
├── remote-connectivity/
├── audit/
└── simpro/

Suggested Admin App Structure

text
apps/admin/src/
├── routes/
│   ├── entity-types/
│   ├── entities/
│   ├── property-groups/
│   ├── tag-groups/
│   ├── templates/
│   ├── groups/
│   ├── relationships/
│   └── audit/

├── features/
│   ├── command-palette/
│   ├── entity-explorer/
│   ├── hierarchy-tree/
│   ├── property-builder/
│   ├── tag-builder/
│   ├── template-builder/
│   ├── relationship-explorer/
│   ├── bulk-operations/
│   └── audit-inspector/

├── components/
├── lib/
│   └── api.ts
└── main.tsx

No Generic Repository Layer By Default

Do not hide Drizzle behind generic repositories unless there is a clear need.

Prefer:

  • services,
  • use-case functions,
  • query helpers,
  • explicit transactions.

This keeps Drizzle autocomplete, inference, relation loading, and SQL composition available to developers.

Contracts

Contracts live in packages/contracts and are shared by backend, frontend, and admin.

Contracts should include:

  • Zod request schemas,
  • Zod response schemas,
  • DTO types,
  • route contract definitions,
  • shared constants.

Contracts must not include database code.

Database Code

Database schema lives in packages/db.

Application behaviour belongs in backend modules, not in the database package.

Use Cases

A use case should represent a meaningful user or system action.

Examples:

  • create entity,
  • move asset,
  • create credential,
  • reveal secret,
  • restore deleted site,
  • apply asset template,
  • add asset to commissioning group,
  • preview Admin Studio bulk update,
  • update property definition.

Use cases should be small, testable, and transaction-aware.

Transactions

Operations that change multiple tables must run inside a transaction.

Examples:

  • create customer entity and customer record,
  • move entity and update descendant paths,
  • soft delete subtree,
  • restore subtree,
  • create secret and audit event,
  • perform Admin Studio bulk update.

Documentation Rule

When a change affects architecture, data model, security, or product behaviour, update docs in the same pull request or commit.

For small solo development, this can simply mean updating the relevant markdown file before marking the feature done.