tsunuga

tango

Learn Japanese while you browse.

Chrome Web Store Render Neon New Relic PostgreSQL

tango is a small learning platform made of two parts:

The extension works locally with bundled lessons and local browser storage. The API is the foundation for account-based and server-backed features.

Production backend

The production API runs on Render, uses Neon-hosted PostgreSQL, and sends application logs and observability data to New Relic.

At a glance

Area Choice
Client TypeScript, React 18, Vite, Chrome Manifest V3
API Go, Echo, JWT
Data PostgreSQL and Redis
Local orchestration Docker Compose and Taskfile
Current state MVP

How it fits together

flowchart LR
    Browser[Web pages] --> Extension[tango Chrome extension]
    Extension --> Local[(Chrome local storage)]
    Extension -->|HTTPS JSON API| API[tango Go API]
    API --> Postgres[(PostgreSQL)]
    API --> Redis[(Redis)]
    Lessons[Lesson YAML] --> Sync[Content sync]
    Sync --> Postgres

Runtime flow

sequenceDiagram
    participant A as Alarm
    participant W as Service worker
    participant T as Active tab
    participant C as Content script
    participant S as Chrome storage

    A->>W: Schedule a practice prompt
    W->>S: Read settings and progress
    W->>T: Find an injectable tab
    W->>C: Send the next card
    C-->>W: Answer or dismiss
    W->>S: Save progress and pending state

What users get

Repository map

.
├── apps/
│   ├── client/                 Chrome extension
│   │   ├── src/background/      Service worker, scheduling, API client
│   │   ├── src/content/         Bundled lessons
│   │   ├── src/contentScript/   Cards injected into web pages
│   │   ├── src/popup/            Toolbar popup
│   │   ├── src/sidepanel/        Progress and controls
│   │   └── src/options/          User settings
│   └── backend/                Go API and content services
│       ├── cmd/                 API and sync entry points
│       ├── content/lessons/     Lesson YAML source
│       ├── internal/handler/    HTTP handlers
│       ├── internal/service/    Application logic
│       ├── internal/database/   Connections and migrations
│       ├── compose.yml          Local PostgreSQL and Redis
│       └── Taskfile.yml         Development commands
└── README.md

Quick start

Requirements

1. Start the API and local services

cd apps/backend
go mod download
cp .env.sample .env
task dev

This starts PostgreSQL and Redis, applies migrations, and runs the Go API with hot reload. Check the API with:

curl http://localhost:8080/status

2. Build the extension

In a second terminal:

cd apps/client
npm install
npm run dev

Then open chrome://extensions, enable Developer mode, choose Load unpacked, and select apps/client/build.

Open a normal http:// or https:// page to try a card. Chrome internal pages, the Web Store, and other restricted pages cannot receive injected cards.

flowchart TD
    Install[npm install] --> Watch[npm run dev]
    Watch --> Build[apps/client/build]
    Build --> Load[Load unpacked in Chrome]
    Load --> Try[Open a normal web page]

Common commands

Run backend commands from apps/backend and client commands from apps/client.

Command Result
task dev Start local services, migrate, and run the API with Air
task test Run all Go tests
task build Build the API binary as bin/tango
task infra:down Stop local services and remove their volumes
npm run dev Watch and build the extension
npm run build Type-check and create a production extension build
npm run zip Build and create a versioned Chrome release archive
npm run fmt Format client source and documentation

API surface

Method Route Auth Use
GET /status None Health check
POST /api/v1/login None Sign in and issue a session/JWT
POST /api/v1/lessons JWT Create lesson content
GET /api/v1/progress JWT Read progress
POST /api/v1/progress/:item_id/attempt JWT Record an attempt
GET /api/v1/settings JWT Read settings
PUT /api/v1/settings JWT Update settings

The local client API default is localhost:8080. Confirm the production API URL, /api/v1 routing, CORS, OAuth client, and authentication flow before connecting a release build to a deployed API.

Configuration

Backend configuration is loaded from the TANGO_* environment variables. Start with apps/backend/.env.sample.

Group Covers
TANGO_PRIMARY_* Environment name
TANGO_SERVER_* Port, timeouts, and CORS
TANGO_DATABASE_* PostgreSQL connection and pool settings
TANGO_REDIS_* Redis address
TANGO_AUTH_* JWT signing configuration
TANGO_INTEGRATION_* External services such as Resend
TANGO_OBSERVABILITY_* Logs, health checks, and New Relic

Do not commit .env files, OAuth secrets, JWT secrets, API keys, or store credentials.

Testing

cd apps/backend && task test
cd apps/client && npm run build

For browser behavior, use the manual checklist in apps/client/TESTING.md. It covers scheduling, quiet hours, pending cards, card types, lesson unlocking, progress, and badge behavior.

Deployment checklist

API

The repository does not yet include a production container, cloud-provider configuration, or CI/CD workflow. The Compose file is for local development dependencies.

Chrome Web Store

cd apps/client
npm run zip

Before uploading the generated archive:

  1. Bump the version in apps/client/package.json.
  2. Test the exact build/ output in a clean Chrome profile.
  3. Verify permissions, icons, OAuth settings, API URL, and HTTPS behavior.
  4. Prepare screenshots, support details, a privacy policy, and store disclosures.
  5. Upload the ZIP through the Chrome Web Store Developer Dashboard and submit it for review.

Store publishing is manual at present.

Privacy and permissions

The extension uses storage, alarms, tabs, scripting, activeTab, sidePanel, and identity permissions. These support local learning state, scheduling, card injection, controls, and Google sign-in. Review the manifest and privacy disclosures before every release.

More detail

Contributing

Keep changes scoped to the relevant app. Run the backend tests, client build, and browser checklist when user-facing behavior changes. Update the relevant README or QA checklist alongside workflow changes.

License

MIT. See apps/client/LICENSE.