Shop It Docs
Portfolio Module

Reference

Every portfolio endpoint, DTO, cache key, and SQL query at a glance

A single-page lookup table for the portfolio module — endpoints, DTOs, cache keys, sqlc queries, and notable file paths.

All 24 endpoints

Every path is prefixed with /api/v1. All require JWT.

Portfolio (tag: Portfolio — 8 endpoints)

MethodPathHandlerStatus
POST/portfolioscore.Handler.Create201
GET/portfolioscore.Handler.List200
GET/portfolios/{id}core.Handler.Get200
GET/portfolios/{id}/summarycore.Handler.GetSummary200
GET/portfolios/{id}/valuationcore.Handler.GetValuation200
GET/portfolios/{id}/broker-analysiscore.Handler.GetBrokerAnalysis200
PATCH/portfolios/{id}core.Handler.Update200
DELETE/portfolios/{id}core.Handler.Delete204

Portfolio Companies (tag: Portfolio Companies — 3 endpoints)

MethodPathHandler
GET/portfolios/{id}/holdingscompanies.Handler.ListHoldings
GET/portfolios/{id}/distributioncompanies.Handler.GetDistribution
GET/portfolios/{id}/companies/{symbol}companies.Handler.GetCompanyDetail

Portfolio Trades (tag: Portfolio Trades — 4 endpoints)

MethodPathHandler
POST/portfolios/{id}/tradestrades.Handler.AddTrade
GET/portfolios/{id}/tradestrades.Handler.ListTrades
PATCH/portfolios/{id}/trades/{tradeId}trades.Handler.UpdateTrade
DELETE/portfolios/{id}/trades/{tradeId}trades.Handler.DeleteTrade

Portfolio Dividends (tag: Portfolio Dividends — 5 endpoints)

MethodPathHandler
POST/portfolios/{id}/companies/{symbol}/dividendsdividends.Handler.AddDividend
GET/portfolios/{id}/companies/{symbol}/dividendsdividends.Handler.ListCompanyDividends
GET/portfolios/{id}/dividendsdividends.Handler.ListPortfolioDividends
PATCH/portfolios/{id}/companies/{symbol}/dividends/{dividendId}dividends.Handler.UpdateDividend
DELETE/portfolios/{id}/companies/{symbol}/dividends/{dividendId}dividends.Handler.DeleteDividend

Portfolio Corporate Actions (tag: Portfolio Corporate Actions — 4 endpoints)

MethodPathHandler
POST/portfolios/{id}/companies/{symbol}/actionsactions.Handler.AddCorporateAction
GET/portfolios/{id}/companies/{symbol}/actionsactions.Handler.ListCorporateActions
PATCH/portfolios/{id}/companies/{symbol}/actions/{actionId}actions.Handler.UpdateCorporateAction
DELETE/portfolios/{id}/companies/{symbol}/actions/{actionId}actions.Handler.DeleteCorporateAction

DTO catalog

Request DTOs

TypeUsed by
core.CreatePortfolioRequestPOST /portfolios
core.UpdatePortfolioRequestPATCH /portfolios/{id}
trades.AddTradeRequestPOST /portfolios/{id}/trades
trades.UpdateTradeRequestPATCH /portfolios/{id}/trades/{tradeId}
dividends.CreateDividendRequestPOST /portfolios/{id}/companies/{symbol}/dividends
dividends.UpdateDividendRequestPATCH .../dividends/{dividendId}
actions.CreateCorporateActionRequestPOST /portfolios/{id}/companies/{symbol}/actions
actions.UpdateCorporateActionRequestPATCH .../actions/{actionId}

Response DTOs

TypeReturned by
core.ResponseCreate, List items, Update
core.DetailResponseGet
core.SummaryResponseGetSummary; embedded in DetailResponse
core.SuspendedSummaryembedded in DetailResponse
core.DistributionBlock + core.SectorBucketembedded in DetailResponse
core.Positionembedded in DetailResponse (positions[])
core.ValuationResponse + core.ValuationPointGetValuation
core.BrokerAnalysisResponse + BrokerAnalysisBucket + BrokerAnalysisItem + BrokerSignalCountsGetBrokerAnalysis
holdings.HoldingResponseListHoldings (the full holdings table)
companies.DistributionResponse + DistributionItemGetDistribution
companies.CompanyPortfolioDetailResponseGetCompanyDetail
companies.CompanySnapshotResponseembedded in CompanyPortfolioDetailResponse
companies.CompanyHoldingResponseembedded; carries WACCBreakdownResponse
companies.WACCBreakdownResponseembedded
companies.FIFOLotResponseembedded (when lots=true)
companies.PortfolioTimelineEventembedded
trades.TradeResponseall 4 trade endpoints
dividends.DividendResponseall 5 dividend endpoints
actions.CorporateActionResponseall 4 action endpoints

Cache keys

KeyTTLDefined in
portfolio:detail:<portfolioID>15scache.PortfolioDetailKey
portfolio:valuation:<portfolioID>:<RANGE>10mincache.PortfolioValuationKey

<RANGE>{1M, 3M, 6M, 1Y, YTD, ALL}.

sqlc queries used

Located in internal/platform/database/queries/. Each tag package's Store interface lists the methods it actually calls.

portfolios.sql:
  CountPortfoliosByCustomer
  FindPortfoliosByCustomer
  FindPortfolioByID                          (ownership guard)
  FindHoldingsWithPricesByPortfolio
  FindPortfolioTradesInRange                 (today's trades for day P&L)
  TouchPortfolioFetchedAt
  FindAllPortfolioTradesForValuation
  FindAllPortfolioCorporateActionsForValuation
  FindBulkPriceHistoryForPortfolio           (ANY($1::uuid[]))

portfolio_companies.sql:
  FindPortfolioCompanyBySymbol
  FindHoldingWithPriceByCompany
  FindOpenLotsByCompany

portfolio_trades.sql:
  FindTradesByPortfolio
  CountTradesByPortfolio

portfolio_dividends.sql:
  FindDividendsByCompany
  FindDividendsByPortfolio

portfolio_corporate_actions.sql:
  FindCorporateActionsByCompany
portfolios.sql:
  CreatePortfolio
  UpdatePortfolio
  SoftDeletePortfolio
  SoftDeleteTradesByPortfolio
  SoftDeleteDividendsByPortfolio
  SoftDeleteCorporateActionsByPortfolio
  DeletePortfolioLotConsumptionsByPortfolio
  DeletePortfolioLotsByPortfolio
  DeletePortfolioHoldingsByPortfolio

portfolio_trades.sql:
  AddTrade
  FindTradeForUpdate
  UpdateTrade
  SoftDeleteTrade
  UpdateTradeAudit                  (called after Rebuild)
  FindSettlementDate
  IsTradingDay
  FindCurrentHoldingForUpdate

portfolio_dividends.sql:
  CreateDividend
  UpdateDividend
  SoftDeleteDividend

portfolio_corporate_actions.sql:
  CreateCorporateAction
  FindCorporateActionForUpdate
  UpdateCorporateAction
  SoftDeleteCorporateAction
portfolio_holdings.sql:
  DeleteLotConsumptionsForHolding
  DeleteLotsForHolding
  FindPortfolioTradesForReplay
  FindDividendsForReplay
  FindCorporateActionsForReplay
  CreatePortfolioLot
  RecordLotConsumption
  UpsertPortfolioHolding
  FindCurrentHoldingForUpdate

File map

internal/modules/portfolio/
├── portfolio.go                                # Module + RegisterRoutes
├── smoke_db_test.go
├── shared/
│   ├── cache.go                                # CacheScope, Invalidator, TxRunner
│   ├── conversions.go                          # ParseTradeTime, ParseDate, DateFromStringPtr,
│   │                                           # DateToStringPtr, StringPtrNonEmpty
│   ├── guard.go                                # FindPortfolio
│   └── store.go                                # PortfolioLookup
├── holdings/
│   ├── replay.go                               # Rebuild + CurrentUnitsForHolding
│   ├── replay_types.go                         # replayLot, replayConsumption, replayEvent
│   ├── daypnl.go                               # DayPnL + sameDayBuyLot
│   ├── view.go                                 # HoldingResponse + HoldingFromRow
│   ├── store.go
│   └── holdings_test.go
├── core/                                       # tag: Portfolio
│   ├── service.go                              # 8 methods
│   ├── handler.go                              # 7 handlers
│   ├── types.go
│   ├── valuation.go                            # buildValuation + range helpers
│   ├── mappers.go                              # portfolioToDTO, detailToDTO
│   ├── store.go
│   ├── handler_test.go
│   └── valuation_test.go
├── companies/                                  # tag: Portfolio Companies
│   ├── service.go                              # 3 methods
│   ├── handler.go                              # 3 handlers
│   ├── types.go
│   ├── distribution.go                         # buildDistribution
│   ├── mappers.go                              # 9 helpers
│   ├── store.go
│   ├── handler_test.go
│   └── distribution_test.go
├── trades/                                     # tag: Portfolio Trades
│   ├── service.go                              # 4 methods
│   ├── handler.go                              # 4 handlers + parseTradeFilter
│   ├── types.go                                # AddTradeRequest, UpdateTradeRequest, TradeResponse, TradeFilter
│   ├── calc.go                                 # broker rate, fees, totals, mergeTradeUpdate, computeCgtMismatch, tradedAtWarnings
│   ├── mappers.go                              # 3 row→DTO mappers
│   ├── store.go
│   ├── handler_test.go
│   └── calc_test.go
├── dividends/                                  # tag: Portfolio Dividends
│   ├── service.go                              # 5 methods
│   ├── handler.go                              # 5 handlers
│   ├── types.go
│   ├── mappers.go                              # 4 row→DTO mappers
│   ├── store.go
│   └── handler_test.go
└── actions/                                    # tag: Portfolio Corporate Actions
    ├── service.go                              # 4 methods
    ├── handler.go                              # 4 handlers
    ├── types.go
    ├── validation.go                           # corporateActionCreateParams, validateCorporateAction
    ├── mappers.go                              # 3 row→DTO mappers
    ├── store.go
    ├── handler_test.go
    └── service_test.go

Cross-module dependencies

DependencyWhy
internal/platform/cachecache.Cache for Get/SetJSON; key constants.
internal/platform/database/sqlcgenerated query API.
internal/http/responseresponse envelope, error builders.
internal/http/handlerutilMustCustomerID, ParseUUIDParam, DecodeAndValidate.
internal/http/paginationshared pagination params + envelope.
internal/http/middlewareglobal auth + rate-limit middleware.
internal/shared/pgconvnumeric/decimal/null pointer conversions (post Step 12 of refactor plan).
internal/shared/timezoneNPT day boundaries.
github.com/shopspring/decimalmoney math without float drift.
github.com/jackc/pgx/v5/pgtypenullable typed DB values.
github.com/google/uuidv7 ids.

Design references

  • Refactor plan: docs/portfolio/PORTFOLIO_REFACTOR_PLAN.md — the canonical structural decisions.
  • Brief: docs/portfolio/PORTFOLIO_REFACTOR_BRIEF.md — what we're trying to achieve and why.
  • Branch audit: docs/portfolio/PORTFOLIO_BRANCH_AUDIT.md — pre-refactor inventory.
  • Calculation reference (§10 fixtures): trade examples and edge cases used in core/valuation_test.go.

Glossary

TermDefinition
WACCWeighted Average Cost of Capital — over open lots only, excluding sold cost.
LotA single acquisition record: (remaining_qty, cost_per_unit, source, acquired_at).
Lot consumptionA pointer from a SELL trade to the open lots it consumed (with consumed qty + cost).
Cost basis (cb)Open-lot residual cost — what a SELL would draw down from. Distinct from "total invested".
Day P&LToday's change in portfolio value, decomposed into overnight + intraday-buy + intraday-sell legs.
NPTNepal Time (UTC+05:45). Trading session 11:00–15:00 NPT, Mon–Fri.
CGTCapital Gains Tax — Nepalese securities tax on realised SELL profits.
ReceivableT+2 settlement balance from sells not yet settled.
SuspendedCompany status != 'A' — delisted or trading-suspended. Excluded from active summary.