DEV Community

Cover image for I Built a Subscription Tracker in 14 Days Using Angular 20 (And Made $0… Yet)
Karol Modelski
Karol Modelski

Posted on

I Built a Subscription Tracker in 14 Days Using Angular 20 (And Made $0… Yet)

I Built a Subscription Tracker in 14 Days Using Angular 20 (And Made $0… Yet)

Picture this: It’s 2 AM, I’m scrolling through my bank statement, and I see three charges I completely forgot about. Spotify Premium (again?), some AI tool I tried once, and a $29/month “productivity” app I haven’t opened in months.

Sound familiar?

As a senior Angular developer, I had the tools to fix this problem. So I gave myself exactly 14 days to build a complete micro SaaS solution from scratch.

The result? SubTrack — a subscription tracking app that not only solved my problem but taught me more about modern Angular development than months of tutorial-watching ever could.

This article kicks off my new series, “Zero to SaaS in 14 Days”, where I build lean SaaS MVPs end-to-end in tight timeframes and share the raw, real lessons learned along the way.

Here’s the brutally honest story of what worked, what didn’t, and why my “failed” revenue attempt might actually be the biggest win.

🎯 The Problem Everyone Has (But Nobody Talks About)

The $273/Month Subscription Creep

We’re living in the subscription economy, and it’s slowly bleeding us dry:

  • That $9.99 Netflix subscription? It’s now $17.99
  • “Just trying” a new SaaS tool for $19/month… 6 months ago
  • App Store subscriptions you forgot existed
  • Annual renewals that hit like financial surprise parties

The existing solutions? Either clunky mobile apps that feel like enterprise software, or heavyweight financial trackers that want to connect to your entire banking history just to track a few subscriptions.

My “Aha!” Moment

I needed something lightweight, fast, and browser-based. Something that could:

  • Track subscriptions without connecting to my bank
  • Scream at me when renewals are coming up
  • Show me exactly where my money’s going with beautiful charts
  • Work offline and sync later (local-first philosophy)

Most importantly: I wanted to build it with Angular 20’s latest features and see if modern web development could solve this ancient problem elegantly.

🚀 The 14-Day Sprint: Building SubTrack

Day 1–2: The Foundation That Changes Everything

Goal: Set up the bones without getting lost in architecture rabbit holes.

I started with Angular 20’s standalone components and the game-changing signals API. No more modules, no more complex state management — just pure, reactive bliss:

// This is what modern Angular looks like
export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),
    provideZonelessChangeDetection(), // 🔥 Future-proofing
    provideRouter(routes)
  ]
};
Enter fullscreen mode Exit fullscreen mode

The secret sauce? A local-first architecture that starts working immediately:

@Injectable({ providedIn: 'root' })
export class SubscriptionsData {
  // Pure reactive state with signals
  private subscriptions = signal<Subscription[]>([]);

  // Computed properties that update automatically
  totalCost = computed(() =>
    this.subscriptions().reduce((total, sub) => total + sub.cost, 0)
  );

  dueSubscriptions = computed(() =>
    this.subscriptions().filter(sub => this.isNearDue(sub))
  );
}
Enter fullscreen mode Exit fullscreen mode

Why this matters: No loading states, no API failures, no “network required” nonsense. The app just works, instantly.

🚀 Ready to level up your frontend game? Grab the FREE 10-Step Code Review Checklist and catch bugs early 🐞, boost app speed ⚡, and make teamwork easy 🤝. Click to get started - your best code is just one download away! 📋✨

Transform Your Frontend Code Reviews with This Proven 10-Step Checklist!

Day 3–7: The CRUD Revolution

Remember the pain of building CRUD operations? Those days are officially over.

I built a complete subscription management system with:

  • Smart form validation that actually helps users
  • Accessible dialogs that don’t make you want to throw your keyboard
  • Date handling that doesn’t break when timezones get involved

The breakthrough moment came with this date normalization trick:

private isNearDue(subscription: Subscription): boolean {
  // The secret: normalize EVERYTHING to start of day
  const today = new Date();
  today.setHours(0, 0, 0, 0);

  const dueDate = new Date(subscription.nextPaymentDate);
  dueDate.setHours(0, 0, 0, 0);

  const daysUntilDue = Math.ceil(
    (dueDate.getTime() - today.getTime()) / (1000 * 3600 * 24)
  );

  return daysUntilDue >= 0 && daysUntilDue <= 7;
}
Enter fullscreen mode Exit fullscreen mode

The result? No more “why is my notification badge disappearing?” bugs. Pure, predictable date logic that actually works.

Day 8–12: Filters That Don’t Suck

Here’s where most CRUD apps die: terrible search and filtering.

I built something different — a filter system that feels like magic:

interface FilterState {
  searchTerm: string | null;
  category: string | null;
  billingCycle: BillingCycle | null;
  dateRange: { start: Date | null; end: Date | null };
}

// Filter logic that's actually readable
private matchesAllFilters(subscription: Subscription, filters: FilterState): boolean {
  return this.matchesSearchTerm(subscription, filters.searchTerm) &&
         this.matchesCategory(subscription, filters.category) &&
         this.matchesBillingCycle(subscription, filters.billingCycle) &&
         this.matchesDateRange(subscription, filters.dateRange);
}
Enter fullscreen mode Exit fullscreen mode

The magic ingredient? Every filter updates in real-time using Angular signals. Type a letter, see results instantly. Change a date range, boom — filtered results without any loading spinners.

Day 13–14: Charts That Tell Stories

Here’s where SubTrack transformed from “just another CRUD app” to “holy crap, I’m spending HOW much on Adobe?!”

Four chart types that expose the truth about your spending:

// Chart configuration that actually makes sense
const CHART_CONFIG = {
  PIE_WIDTH: 380,
  PIE_WIDTH_MOBILE: 200,
  BAR_HEIGHT: 350,
  MOBILE_BREAKPOINT: 480,
  TOP_SUBSCRIPTIONS_LIMIT: 5
} as const;

private createPieChartOptions(): PieChartOptions {
  const { labels, series } = this.categoryData();
  return {
    series,
    chart: { width: CHART_CONFIG.PIE_WIDTH, type: 'pie' },
    labels,
    responsive: [{ /* Mobile-first approach */ }],
    tooltip: { y: { formatter: CURRENCY_FORMATTER.format } }
  };
}
Enter fullscreen mode Exit fullscreen mode

The moment everything clicked: When I saw that Adobe Creative Cloud was eating $52.99/month of my budget. That single chart paid for the entire development time by helping me realize what subscriptions I could actually cancel.

💡 Plot Twists: What Nobody Tells You

The Bug That Almost Broke Everything

Day 11, 11:47 PM: The notification badge kept disappearing when subscriptions were due “today.”

Hours of debugging later, I discovered the culprit: time-of-day calculations were fighting with day-boundary logic. The fix was embarrassingly simple — normalize everything to midnight:

private normalizeToStartOfDay(date: Date): Date {
  const normalized = new Date(date);
  normalized.setHours(0, 0, 0, 0);
  return normalized;
}
Enter fullscreen mode Exit fullscreen mode

Lesson learned: Sometimes the most frustrating bugs have the most elegant solutions.

The Feature That Became The App

Originally, the notification badge was just a nice-to-have. But when I implemented the 7-day “near due” window, suddenly the entire app made sense.

Users don’t want to manage subscriptions — they want to forget about them until it matters.

That badge became the single most important feature, turning SubTrack from a database into a personal financial assistant.

🔍 The Technical Deep-Dive That Changed My Mind

Why Angular 20 + Signals = Developer Happiness

After building this app, I’m convinced that Angular’s signals are the future of reactive programming:

// Old way: Complex RxJS chains, memory leaks, subscription hell
this.filteredData$ = this.searchTerm$.pipe(
  debounceTime(300),
  distinctUntilChanged(),
  switchMap(term => this.filterData(term)),
  shareReplay(1)
);

// New way: Pure reactive bliss
readonly filteredData = computed(() => {
  const term = this.searchTerm();
  const filters = this.filters();
  return this.filterData(term, filters);
});
Enter fullscreen mode Exit fullscreen mode

No subscriptions to manage. No memory leaks. No async pipe headaches. Just pure, predictable reactivity.

The Local-First Architecture That Actually Works

Most apps start with “let’s build an API first.” I did the opposite — local storage with a migration path:

@Injectable({ providedIn: 'root' })
export class LocalStorageApi {
  // Defensive programming that prevents data loss
  getItems<T>(key: string): T[] {
    try {
      const items = localStorage.getItem(key);
      if (!items) return [];
      const parsed = JSON.parse(items);
      return Array.isArray(parsed) ? parsed : [];
    } catch (error) {
      console.error(`Error parsing localStorage data for key ${key}`, error);
      this.clearItem(key); // Fail gracefully
      return [];
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Result: Zero infrastructure costs, instant app startup, and users can try it without signing up for anything.

📈 The Results That Surprised Me

What Worked Better Than Expected

  1. Angular 20’s standalone components eliminated so much boilerplate
  2. Local-first architecture made the app feel incredibly fast
  3. Material 3 theming gave professional UI with minimal effort
  4. Signals + computed properties made complex state trivial

What I’d Do Differently

  1. Start with a domain layer from day one (too much logic ended up in components)
  2. Prepare for internationalization/multi-currency support: Early architecture choices to support different locales make expanding beyond initial markets easier.
  3. Invest in automated testing early: Setting up unit and integration tests before feature creep means faster iterations and less bug hunting closer to launch.
  4. Prototype key interactions before full implementation: Rapid clickable prototypes might have highlighted UX challenges earlier and saved development time.

The $0 Revenue Reality Check

Here’s the uncomfortable truth: I made exactly $0 from SubTrack.

But here’s why that doesn’t matter:

  • Validated the local-first approach for future projects
  • Mastered Angular 20’s signals before they become mainstream
  • Built a portfolio piece that showcases modern development practices
  • Learned what users actually want in subscription management

Sometimes the biggest wins don’t show up in your bank account immediately.

🎪 The “Holy Crap” Moment That Made It All Worth It

Day 14, 3:22 PM: I deployed the final version and opened the spending overview.

The top 5 chart showed:

  • Adobe Creative Cloud: $52.99/month
  • Coursera Plus: $39.99/month
  • Prime + Music: $16.98/month
  • ChatGPT Plus: $20.00/month
  • Some random productivity app: $29.99/month

Total: $159.95/month I wasn’t fully conscious of.

At that moment, SubTrack stopped being a coding exercise and became a financial wake-up call. I immediately canceled two subscriptions and saved $69.98/month.

The app paid for itself before I even tried to monetize it.

🚀 Help Me Build SubTrack That Works For You!

SubTrack is just getting started. To shape the future of subscription management, your feedback is everything. Please take a moment to answer these few key questions:

  • What’s your biggest frustration with subscription tracking today?
  • Which SubTrack feature do you find most useful or exciting?
  • What one feature is missing that would make you use SubTrack daily?
  • Would you pay around $5/month for extra perks like multi-device sync, export, or alerts?
  • How important is data privacy and local-first storage to you?
  • Would you trust SubTrack to handle your subscription data securely?
  • How do you want to be notified about upcoming payments? (Email, SMS, in-app)
  • If you’re using another tool, what would make you switch to SubTrack?

Your answers guide my roadmap — let’s build the subscription manager you actually want.

Drop your thoughts below or reach out anytime!

💬 Your Turn: Let’s Build Something Amazing Together

This 14-day sprint showed me the best products solve real problems. SubTrack was born from my own subscription shock moments.

What’s your biggest problem you’d solve if you had two weeks and modern tools?

Try SubTrack now:

👉 Try the SubTrack app now!

Your feedback will shape what comes next. Drop a comment or DM me anytime.

Sometimes, the best way to fix a problem is to build the solution yourself.

Want more behind-the-scenes? Follow me for updates on my next 14-day challenge . 🔥


Thanks for Reading 🙌

I hope these tips help you ship better, faster, and more maintainable frontend projects.

🛠 Explore My Developer Resources
Save time and level up your code reviews, architecture, and performance optimization with my premium Angular & frontend tools.
👉 Browse on Gumroad

💬 Let's Connect on LinkedIn
I share actionable insights on Angular & modern frontend development - plus behind‑the‑scenes tips from real‑world projects.
👉 Connect with me here

📣 Follow Me on X
Stay updated with quick frontend tips, Angular insights, and real-time updates - plus join conversations with other developers.
👉 Follow me on X

Your support fuels more guides, checklists, and tools for the frontend community.

Let's keep building together 🚀

Top comments (1)