Ark Clam Academy
BrownbrickA workplace training app for German companies, with Whisper-generated English and German subtitles, translated quizzes, a fully localised Flutter client, and WebSocket team chat.
About this project
Ark Clam Academy is a training app for German companies. Staff watch short instructional videos, take quizzes on them, and their managers can see who has finished what.
There are four roles. A CEO account runs the platform, admins manage organisations and their licences, supervisors create training for their teams, and employees work through it, mostly on their phones. The client is a Flutter app for Android and iOS. It talks to a FastAPI backend on PostgreSQL, with Celery workers for slow jobs and DigitalOcean Spaces for video. I worked across the mobile app and the backend for about six months, as one of a small team.
Not everyone watching was a native German speaker, so the videos had to work in two languages.
Subtitles in two languages, generated for you
I built the transcription pipeline. When a supervisor uploads a video, the API stores it straight away and returns, then queues one Celery task per language, English and German. Each task sends the audio to OpenAI's Whisper, asks for subtitles in SRT format, uploads the file next to the video, and links it to the video in the database. Because this runs in the background, a long upload never holds up the request, and adding a language is a one-line change. On the app side, the player loads every subtitle track for the video, with one selected by default, and viewers can switch between them. That needed fixes for streaming performance and for video playback on iOS.
Quizzes needed the same treatment. Titles, descriptions, and questions are machine-translated when they're saved and stored as separate translation rows, so an employee sees the whole quiz in their own language and the scores still point to a single question.
An app that speaks German first
The app was first written with English strings scattered through the code. I set up Flutter's localisation system and moved every user-facing string into English and German resource files, around 340 keys. That covered the CEO home screen, organisation details, the tables, the modals, the quiz builder, and the settings. The language selector in settings switches locale across the whole app at once, and API calls send that locale so the server answers in the same language. I also added username logins next to email, since many employees didn't have a work email address.
Team chat
Toward the end I built chat from end to end. Chat rooms belong to an organisation, have participants, and can be one-to-one or group conversations. Messages are saved through the REST API and pushed to everyone in the room over an authenticated WebSocket. In the app there is a chat sidebar, a conversation view, and a way to add people to an existing group.
At a glance
- — Four roles: CEO, admin, supervisor, employee
- — Whisper subtitles in English and German
- — Celery workers so uploads return straight away
- — Translated quizzes stored per language
- — Full localisation of the Flutter app
- — WebSocket chat with group rooms
- — Username or email sign-in
- — Terraform and CI for the backend deploy
Localisation is far cheaper to plan for from the start. Most of the work wasn't translating anything. It was finding every string that had been typed straight into a widget.