Back to projects

Published on the App Store

PolyLog

A language-learning app that carried a write → feedback → review loop from a 12-hour MVP to the App Store.

A language-learning app inspired by study-group members who struggled with delayed writing feedback and separate vocabulary tracking. My first Flutter product began as a 12-hour MVP, connected AI feedback with review and learning records, and shipped to the App Store as a solo release.

Period
2025.10 - 2025.12
Ownership
Full app · AI feedback · App Store delivery
Team
Solo
Repository
Private repository

The feedback gap immediately after writing

Members of my Japanese study group told me they could not quickly check whether a diary entry sounded natural, and that looking up and recording unfamiliar words elsewhere was cumbersome. Writing and vocabulary review had become separate tasks.

For the 12-hour hackathon, I focused on one loop—diary, AI feedback, saved vocabulary, and review—rather than expanding into community features.

Learning loop

From writing a diary entry to the next review

  1. 01

    Write a diary

    The learner's writing

  2. 02

    AI feedback

    Corrections and explanations from Gemini

  3. 03

    Save progress

    Diary and vocabulary in Firebase

  4. 04

    Review on device

    Vocabulary and review state in Hive

A boundary between free-form AI output and the screen

If Gemini omitted a field or changed its response shape, the feedback screen could not read the data it expected.

The 12-hour MVP needed a small design that kept the API key out of the client and let Flutter distinguish success, failure, and retry states.

I routed Gemini requests through Firebase Functions, constrained output with JSON mode, and mapped it into screen models with JSON.parse. Runtime schemas, automatic retries, and error logging are not implemented.

  • Specified required fields through the prompt and JSON mode.
  • Kept the Gemini API key in Firebase Functions.
  • Mapped JSON.parse results into Flutter feedback models.

Version 1.0.1 shipped on the App Store with this path. Delivery is verified; parsing success, latency, and missing-field rates were not measured.

I learned that asking for JSON is not a contract; failure becomes manageable only with runtime validation, retries, and logging.

PolyLog diary writing screen

Dividing Firestore and Hive roles for faster review

Vocabulary review moves through many small items and updates review state frequently. Waiting for Firestore on every card would make a short study flow depend on network conditions.

This was a solo app that began as a 12-hour MVP, so a full offline-first synchronization system was out of scope. Making the device the only source of truth also conflicted with the Firebase-based user-data model.

I kept Firestore as the remote source of truth, copied vocabulary into Hive during login and initial sync, and served routine list and review reads locally. Mutations update both the remote record and local cache.

  • Synchronized Firestore vocabulary into Hive after login.
  • Built vocabulary lists and review order from local state.
  • Applied additions and review-state changes to both Firestore and Hive.

The App Store release includes this data path. I did not measure before-and-after request counts or render time, and offline conflict handling is not yet documented.

I learned that adding a local cache is not only a read optimization; it requires an explicit source of truth and synchronization boundary.

PolyLog vocabulary screen

I shipped version 1.0.1 to the App Store. The available aggregate count shows roughly 30 total downloads.

Shipping my first service to the App Store gave me a strong sense of accomplishment. As my first Flutter product, I implemented the client flow that shows loading before a request, maps backend responses into screen state, and offers a retry after failure. I now consider whether an API returns the response shape and error information the screen needs for those branches.

I do not claim a causal relationship with JLPT results. Gemini parsing success, latency, and performance improvements were not measured.

  • Add runtime schema validation, retry, and error logging for Gemini
  • Document Firestore/Hive sync and offline conflict policy
  • Decide how to measure and maintain the current app