Skip to content

Implement BudgetsService and AnalyticsService with real database queries #111

Description

@grantfox-oss

Description

Priority P1

Type / Area feature, backend, budgets, analytics

Suggested Complexity High

Summary src/budgets/budgets.service.ts and src/analytics/analytics.service.ts are both status-only scaffolds. There are also two analytics modules (src/analytics/ and src/analytics-system/) with no distinction between them. Build BudgetsService with full CRUD backed by a new budgets table, and build AnalyticsService with real queries against the existing transactions table — spending trend, category breakdown, and budget-vs-actual. Consolidate the two analytics modules into one.

Problem Both services are identical scaffolds:

typescript
// src/budgets/budgets.service.ts — current state
status(): { module: string; status: string } {
return { module: 'budgets', status: 'ready' };
}

// src/analytics/analytics.service.ts — current state
status(): { module: string; status: string } {
return { module: 'analytics', status: 'ready' };
}

Additionally src/analytics-system/analytics-system.service.ts is an identical third scaffold with no documented purpose distinct from src/analytics/. The duplication exists because a second analytics module was generated without a clear responsibility boundary — a DEAD_CODE_TICKETS entry was flagged for this exact issue in the contracts repo's companion doc. The stellarspend-app analytics page calls GET /analytics/trend, GET /analytics/category-breakdown, and GET /analytics/budget-vs-actual — all three return { module: 'analytics', status: 'ready' } today.

Scope

In Scope

New migration: src/migrations/1710000000004-create-budgets-table.ts — budgets(id uuid PK, user_id uuid NOT NULL, name varchar(80), asset varchar(12), amount numeric(30,12), category varchar(80), period varchar(20) DEFAULT 'monthly', start_date date, end_date date, created_at timestamptz, updated_at timestamptz)
New entity: src/budgets/entities/budget.entity.ts
BudgetsService: create, findAll(userId), findOne(userId, id), update(userId, id, dto), remove(userId, id) — standard CRUD with ownership checks
AnalyticsService:
getSpendingTrend(userId: string, asset: string, weeks: number): Promise<{ week: string; total: string }[]> — groups transactions by ISO week using PostgreSQL date_trunc
getCategoryBreakdown(userId: string, asset: string, since: Date): Promise<{ category: string; total: string; percentage: string }[]> — sums by category, computes percentage of grand total in SQL
getBudgetVsActual(userId: string): Promise<{ budgetName: string; budgeted: string; actual: string; variance: string }[]> — joins budgets to transactions on category and asset, computes variance
Delete src/analytics-system/ entirely — move any unique content to src/analytics/ and remove the module from app.module.ts
Wire BudgetsService and AnalyticsService into their controllers with @UseGuards(JwtAuthGuard)
Unit tests for both services

Out of Scope

Changing the TransactionEntity schema
Real-time streaming analytics

Files src/budgets/budgets.service.ts (rewrite) src/budgets/budgets.controller.ts (rewrite) src/budgets/budgets.module.ts (modify) src/budgets/entities/budget.entity.ts (new) src/analytics/analytics.service.ts (rewrite) src/analytics/analytics.controller.ts (rewrite) src/analytics/analytics.module.ts (modify) src/analytics-system/ (delete entire folder) src/app.module.ts (modify — remove AnalyticsSystemModule) src/budgets/budgets.service.spec.ts (new) src/analytics/analytics.service.spec.ts (new) src/migrations/1710000000004-create-budgets-table.ts (new)

Acceptance Criteria

Full CRUD on /budgets with ownership validation
GET /analytics/trend?asset=USDC&weeks=8 returns 8 weekly buckets with real aggregated totals from the transactions table
GET /analytics/category-breakdown?asset=XLM&since=2026-01-01 returns categories with percentage computed in SQL
GET /analytics/budget-vs-actual returns per-budget variance using real spend data
src/analytics-system/ folder no longer exists and app.module.ts does not import AnalyticsSystemModule
New migration runs cleanly
npm test -- budgets and npm test -- analytics both pass

How to Test Create a budget (POST /budgets) for "Groceries" 200 USDC monthly. Sync transactions containing USDC Groceries spend. Call GET /analytics/budget-vs-actual — verify the Groceries budget row shows real spend vs 200 USDC. Call GET /analytics/trend?asset=USDC&weeks=4 — verify 4 weekly rows. Call GET /analytics/category-breakdown?asset=USDC — verify percentages sum to 100%.

PR Requirements

CI checks must pass
npm test passes
Include screenshots of test results
Link issue using Closes #ISSUE_NUMBER

Project Links Repository: https://github.com/stellarspend/stellarspend-api Community: https://t.me/+7RpAgpVggOphNzJk

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions