Skip to content

akin-oz/energy-portfolio-slice

Repository files navigation

Energy Portfolio Slice

This repo is a small, end‑to‑end vertical slice of an energy portfolio product. It shows how I work: model the domain first, define a clear contract, implement behind stable seams, and keep change safe with tests.

The slice includes:

  • A domain package with rules and factories
  • A GraphQL API shaped around real user queries
  • DynamoDB Local persistence behind repository interfaces
  • A React app consuming the real API
  • Local infra, seed scripts, and both unit and integration tests

This repo demonstrates how I think, not how many features I can ship.


What’s in the repo

Domain core

packages/domain

  • Types: Customer, Project, EnergyAsset
  • Enums: ProjectStatus, EnergyAssetType
  • Validation helpers for invariants
  • Factories and seed helpers
  • Unit tests for rules and edge cases

Shared utilities

packages/shared

  • Typed error helpers
  • Cursor pagination helpers used by the API

GraphQL API

services/api

  • Schema in schema.graphql
  • Queries:
    • customer(id)
    • customers(first, after)
    • projectsByCustomer(customerId, first, after, status)
    • energyAssetsByProject(projectId, first, after, type)
  • Thin resolvers with no business logic
  • Pagination and filtering tests

Persistence

services/api/src/repository

  • interfaces.ts defines seams
  • inMemory.ts for fast tests
  • dynamo.ts adapter for DynamoDB Local
  • Lists sorted by createdAt then id for stable cursors

Web app

apps/web

  • React + Vite + TypeScript
  • Apollo Client
  • Panels for customers, projects, and assets

Architecture

The slice follows a strict order:

  1. Domain defines rules and shapes
  2. Contract exposes those shapes with GraphQL
  3. Repository hides DynamoDB and storage details
  4. UI interacts only with the contract

No GraphQL types leak into the domain. No DynamoDB calls leak into resolvers.

This keeps the system testable, replaceable, and easy to extend.


Repo layout

├─ packages/
│  ├─ domain/
│  └─ shared/
├─ services/
│  └─ api/
├─ apps/
│  └─ web/
├─ local/
└─ vitest.workspace.ts

Run locally

1. Install

pnpm install

2. Start DynamoDB Local

pnpm db:up

3. Seed data

pnpm seed

4. Start the API (Dynamo mode)

pnpm dev:api:dynamo

API runs at: http://localhost:4000/graphql

5. Start the web app

pnpm dev:web

Web runs at: http://localhost:5173

Tests

# Unit + fast tests
pnpm test

# Dynamo integration tests (DB must be running)
pnpm db:up && pnpm test:api:dynamo

Example GraphQL queries

query CustomerById {
  customer(id: "cust_1") {
    id
    name
    createdAt
  }
}

query Customers {
  customers(first: 10) {
    edges { cursor node { id name createdAt } }
    pageInfo { hasNextPage endCursor }
  }
}

query ProjectsByCustomer {
  projectsByCustomer(customerId: "cust_1", first: 10, status: ACTIVE) {
    edges { cursor node { id name status createdAt } }
    pageInfo { hasNextPage endCursor }
  }
}

query EnergyAssetsByProject {
  energyAssetsByProject(projectId: "proj_3", first: 10, type: SOLAR) {
    edges { cursor node { id type capacityKw active createdAt } }
    pageInfo { hasNextPage endCursor }
  }
}

Design principles

Domain first — rules live in packages/domain.

Contract first — GraphQL schema follows user flows.

Stable seams — repositories abstract persistence.

Small slices — layers stay independent and testable.

Change‑safe — pagination and filters have tests to prevent drift.


Fast review path

If you want a 30–45 minute review:

  1. Domain types: packages/domain/src/types.ts
  2. Validation: packages/domain/src/validation.ts
  3. GraphQL contract: services/api/src/graphql/schema.graphql
  4. Repositories: services/api/src/repository
  5. UI panels: apps/web/src/components

What I would extend next

If this were to grow beyond a portfolio slice:

  1. Auth + roles (JWT, API key, role map)
  2. Error taxonomy (consistent domain → GraphQL mapping)
  3. Batching (Dataloader for list queries)
  4. Observability (trace IDs, structured logs)
  5. CI + Deploy (schema drift check, test matrix, minimal AWS deploy)

Roadmap status

Done:

  • Domain model
  • GraphQL contract
  • DynamoDB persistence
  • Pagination + filtering
  • React slice
  • Local infra + seeding

Optional next steps:

  • Auth / roles
  • Error taxonomy
  • Tracing and batching
  • Workflow mutation + events
  • Deployment story

About

Vertical slice for an energy portfolio platform – TypeScript, GraphQL, React, contracts-first, testable.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors