polar-local-environment
This skill should be used when setting up or managing Polar local development environment with Docker.
Install
npx skills add https://github.com/fcakyon/claude-codex-settings/tree/main/plugins/polar-skills/skills/polar-local-environment
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install fcakyon-claude-codex-settings@llmmart
git clone https://github.com/fcakyon/claude-codex-settings.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole fcakyon/claude-codex-settings collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Local Environment Skill
Helps manage the Polar local development environment through the dev docker
CLI. Use it to start, stop, debug, or reason about the local stack.
The two-part model
dev docker deliberately splits the stack so many worktrees can share one set
of heavy infra:
- Shared infra — one copy per machine, Docker project
polar-shared: postgres, redis, minio, tinybird, and optional prometheus/grafana. Postgres and redis publish no host ports; MinIO exposes 9000/9001 for browser uploads. Usedev docker exec <service> ...for services without host ports. - Per-instance app stack — one per worktree, project
polar-app-<N>: api, worker, web. Only api and web publish host ports, offset per instance so worktrees don't collide.
Knowing this prevents the most common confusion: there is no localhost:5432
for the database (it lives in the shared stack and is reached through
dev docker exec db ...). MinIO does expose ports 9000/9001 for browser
uploads and console access.
Instance auto-detection
dev docker auto-detects the instance for the current worktree, so -i is
rarely needed. Priority:
POLAR_DOCKER_INSTANCEpinned indev/docker/.env.docker(dev docker set-instance N)CONDUCTOR_PORTenv var →(port - 55000) / 10 + 1- The cross-worktree registry (
~/.config/polar/docker-instances.json) - Otherwise the lowest free number, then registered
Run dev docker ports to see the resolved instance and its URLs (add --json
for tooling). To wire this worktree into Claude Code's preview, run
dev docker launch-json, which writes a per-instance .claude/launch.json with
the correct ports (it's gitignored, so regenerate after set-instance).
When to use
- Start / stop / restart the local environment
- View logs or debug a service that won't come up
- Run several isolated worktree instances in parallel
- Understand the service architecture or find a service's real port
- Diagnose container or first-boot errors
Quick reference
| Task | Command |
|---|---|
| Start full stack (background) | dev docker up -d |
| Start and block until healthy | dev docker up -d --wait |
| Start in foreground (stream logs) | dev docker up --no-detach |
| Rebuild with fresh base images | dev docker up -b --pull -d |
| Show this instance's ports/URLs | dev docker ports (--json for tooling) |
| Write Claude Code preview config | dev docker launch-json |
| Stop app stack | dev docker down |
| Stop app and shared infra | dev docker down --all |
| Follow logs | dev docker logs -f [service] |
| Print logs and exit | dev docker logs --no-follow [service] |
| Status | dev docker ps |
| Restart a service | dev docker restart <service> |
| Shell into a service | dev docker shell <service> |
| One-off command in a service | dev docker exec <service> <cmd> |
| Reset this instance | dev docker cleanup -f |
| Wipe ALL shared data | dev docker cleanup --all -f |
| List every instance | dev docker list |
| With monitoring | dev docker up --monitoring -d |
Services
| Service | Project | Host port (instance 0 / N) | Notes |
|---|---|---|---|
| api | polar-app-<N> |
8000 / 8100+N | FastAPI; /healthz healthcheck |
| web | polar-app-<N> |
3000 / 3100+N | Next.js; healthchecked |
| worker | polar-app-<N> |
none | Background jobs |
| db | polar-shared |
none (exec) |
PostgreSQL; DB polar_dev_<N> |
| redis | polar-shared |
none (exec) |
Redis DB index = N |
| minio | polar-shared |
9000, 9001 | S3; buckets polar-s3-<N>; console at 9001 |
| tinybird | polar-shared |
none (exec) |
Analytics |
| prometheus / grafana | polar-shared |
none (exec) |
--monitoring only |
Discover the exact host ports for the current worktree with dev docker ports.
Instance port mapping
Only api and web get host ports: Port = Base + Instance (Base 8100 for api,
3100 for web) for instances 1–99. Instance 0 uses the legacy 8000 / 3000.
| Instance | API | Web |
|---|---|---|
| 0 | 8000 | 3000 |
| 1 | 8101 | 3101 |
| 2 | 8102 | 3102 |
| 5 | 8105 | 3105 |
Everything else is per-instance but not on a host port: database polar_dev_<N>,
redis DB index <N>, buckets polar-s3-<N> / polar-s3-public-<N>. Reach them
via dev docker exec <service> or docker exec polar-shared-<service>-1.
Rules index
| Rule | Category | Description |
|---|---|---|
| service-architecture | Reference | Service details, ports, healthchecks |
| start-environment | Operations | Starting the stack (flags, --wait, --pull) |
| stop-environment | Operations | Stopping and cleanup (app vs shared) |
| manage-instances | Operations | Parallel worktree instances |
| view-logs | Debugging | Viewing service logs |
| shell-and-workflows | Operations | Shell access and common dev workflows |
| troubleshooting | Debugging | Common errors and fixes |
| payment-testing | Operations | Login codes, Stripe webhooks, backoffice |
Files (claude-codex-settings)
-
rules
-
manage-instances.md 2.7 KB
--- title: Managing Multiple Instances category: Operations tags: instances, parallel, isolation --- # Managing Multiple Instances ## What are instances? An instance is one worktree's isolated app stack (project `polar-app-<N>`). All instances share a single infra stack (`polar-shared`), but each gets: - Its own api/web **host ports** (offset per instance) - Its own database `polar_dev_<N>` on the shared postgres - Its own redis DB index `<N>` on the shared redis - Its own S3 buckets `polar-s3-<N>` / `polar-s3-public-<N>` on the shared minio So instances are cheap: only api/worker/web containers are duplicated, not the infra. ## Port mapping Only api and web publish host ports. Everything else is shared and reached by container name, so there is **no** per-instance `5532`/`6479`/`9100` — those ports don't exist in this model. | Service | Instance 0 | Instance 1 | Instance 2 | |---------|------------|------------|------------| | API (host) | 8000 | 8101 | 8102 | | Web (host) | 3000 | 3101 | 3102 | | DB (logical) | `polar_dev_0` | `polar_dev_1` | `polar_dev_2` | | Redis (DB index) | 0 | 1 | 2 | | S3 bucket | `polar-s3-0` | `polar-s3-1` | `polar-s3-2` | **Host-port formula (api/web only):** `Port = Base + Instance` (Base 8100 for api, 3100 for web), for instances 1–99. Instance 0 uses the legacy `8000`/`3000`. So instance 5 is api `8105` / web `3105`. Run `dev docker ports` in a worktree to print its resolved instance and URLs. ## Pinning and inspecting instances Auto-detection usually picks the right instance, but you can pin or inspect: ```bash dev docker set-instance 5 # pin this worktree to instance 5 (writes .env.docker + registry) dev docker clear-instance # back to auto-detect dev docker list # every registered instance: number, status, path dev docker prune # drop registry entries whose worktree is gone, and their data ``` Pinning makes ports deterministic, which is what you want when wiring a worktree into tooling like `.claude/launch.json`. ## Commands (explicit instance) Most commands auto-detect, but `-i N` targets one explicitly: ```bash dev docker up -i 1 -d # start instance 1 dev docker ps -i 1 # status dev docker logs -i 1 api # logs dev docker down -i 1 # stop dev docker shell -i 1 api # shell ``` ## Use cases - **Branch A vs branch B** side by side, each in its own worktree. - **Run a long test suite** in one instance while developing in another. - **Before/after comparisons** without tearing down your main stack. ## Resource notes Each app stack adds ~2 GB and its own build/cache volumes; the shared infra is paid once. Two or three instances is comfortable on a typical machine. Use `dev docker prune` to reclaim data from worktrees you've deleted. -
payment-testing.md 6.2 KB
--- title: Testing Auth and Payment Flows Locally category: Operations tags: stripe, dramatiq, auth, backoffice, checkout --- # Testing Auth and Payment Flows Locally Most non-trivial bug reports against the local stack touch one of: login, Stripe webhooks, subscription renewals, refunds, or the backoffice. These all have small environmental quirks that aren't obvious from the source — this rule collects them in one place. ## Logging In Email login codes are printed in the api container logs as a banner: ``` ╔══════════════════════════════════════════════════════════╗ ║ 🔑 LOGIN CODE: ABCDE1 ║ ╚══════════════════════════════════════════════════════════╝ ``` Grab the latest one: ```bash docker logs --since 30s polar-app-<N>-api-1 2>&1 | grep -A1 "LOGIN CODE" ``` Use `admin@polar.sh` as the default test account — the seed creates it with an approved org (`admin-org`) that already has a payout account, identity verification, and at least one product. That lets you go straight to checkout testing without onboarding work. ## Stripe Sandbox and Webhooks ```bash dev stripe --listen # or, for a non-default instance, pass the API port from `dev docker ports`: dev stripe --listen --port <api-port> ``` Local environments always run against a **personal Stripe sandbox** — never a live account, and never a shared team account. `dev` refuses both with one structural check: the linked profile must hold test keys, and since a sandbox has no live mode at all, the Stripe CLI must have stored no live key for it. A shared team account is a live account, so it fails that check. The Stripe CLI profile is always named `polar-sandbox`, so `dev` never depends on whichever account the CLI happens to have active. Pass `-p polar-sandbox` when running `stripe` by hand. `dev stripe --listen` handles the full setup in one step: installs the Stripe CLI if missing, walks through creating/linking a sandbox, writes `POLAR_STRIPE_SECRET_KEY`, `POLAR_STRIPE_PUBLISHABLE_KEY`, and `POLAR_STRIPE_WEBHOOK_SECRET` into the central secrets file, runs `dev/setup-environment` to propagate them, and then starts `stripe listen` forwarding to both the regular webhook endpoint and the Stripe Connect endpoint (`/v1/integrations/stripe/webhook` and `/v1/integrations/stripe/webhook-connect`). Re-running it later just starts the listener. `dev stripe --relink` switches to a different sandbox. Stripe CLI keys expire after 90 days. An expired key shows up as `The API key provided has expired` — `dev stripe` detects it and re-runs the link flow. `--port` defaults to `8000`. Conductor worktrees and multi-instance setups land outside the 0–2 base-port table, so read the api port from `dev docker ports` rather than computing it. Leave it running and `stripe listen` will log each event with the API's 2xx response. Missing webhook → confirm the api port matches `dev docker ports`. One listener signs both endpoints, so `POLAR_STRIPE_WEBHOOK_SECRET` and `POLAR_STRIPE_CONNECT_WEBHOOK_SECRET` hold the same value. If they already differ, they came from dashboard endpoints and `dev stripe` leaves them alone. ## Taxes `dev stripe` reports on Stripe Tax, because checkout can't price an order without it: - **inactive/pending** — checkout fails with a tax calculation error. Activate Stripe Tax in the sandbox (it needs a head office address). - **active, no registrations** — checkout works, every order is taxed at 0. - **active with registrations** — the countries are listed. To test real tax, add a registration under Tax > Registrations in the sandbox: pick "I've already registered", then "Non-Union One-Stop Shop (OSS)" for Ireland, starting immediately. EU countries then get VAT (Ireland 23%, Sweden 25%, and so on). Tax applies per the customer's billing country, so a US-only registration leaves EU orders at 0. ## Checkout Email Validation The checkout form rejects email addresses whose domain looks fake. Two common gotchas: - `.local` TLDs fail with "reserved name that cannot be used with email" - `example.com` fails with "domain does not accept email" Use a real domain with a `+tag` to keep tests isolated: `yourname+test-foo@polar.sh`. ## Triggering Dramatiq Actors Manually Some flows (notably subscription renewals) are driven by background jobs that normally fire on a schedule. To force one immediately, enqueue the actor from inside the api container: ```bash docker exec polar-app-<N>-api-1 sh -c 'cd /app/server && uv run python -c " import asyncio, dramatiq import polar.tasks # registers every actor as a side-effect of import from polar.worker import JobQueueManager, enqueue_job from polar.redis import create_redis async def main(): redis = create_redis(\"worker\") async with JobQueueManager.open(dramatiq.get_broker(), redis): enqueue_job(\"<actor.name>\", *args) asyncio.run(main()) "' ``` Two non-obvious bits: - `import polar.tasks` is required. Without it, the broker has no registered actors and `enqueue_job` raises `dramatiq.errors.ActorNotFound`. - The `JobQueueManager.open(...)` context manager is what flushes the queued message to Redis. Without it, `enqueue_job` raises `LookupError` on the `polar.job_queue_manager` context var. ### Useful actors | Actor | Args | Notes | |-------|------|-------| | `subscription.cycle` | `subscription_id, force` | Advances one period. `force=True` ignores `current_period_end` — use it to fake renewals or to drive `cancel_at_period_end` subscriptions to their final cancel. | ## Inspecting the Backoffice The backoffice is mounted at `http://localhost:<api-port>/backoffice/` and uses the same session cookie as the dashboard, so logging into the dashboard also authenticates you here. Useful for verifying merchant-side state (balance, review status, transactions, audit logs) without writing SQL. A direct DB cross-check is still cheap and worth running when investigating balance/transaction issues: ```bash dev docker exec db psql -U polar -d polar_dev_<N> -c \ "SELECT total_balance FROM organizations WHERE slug='admin-org';" ``` -
service-architecture.md 3.1 KB
--- title: Service Architecture Reference category: Reference tags: architecture, services, infrastructure --- # Service Architecture Reference Two Docker projects: shared infra (`polar-shared`, one per machine) and a per-instance app stack (`polar-app-<N>`, one per worktree). Shared infra publishes **no host ports** — reach it with `dev docker exec <service> ...`. ## Infrastructure services (project `polar-shared`) ### db (PostgreSQL 15.1) - Primary database. Reached at `db:5432` on the `polar-shared` network. - Credentials: `polar` / `polar`. - One logical database per instance: `polar_dev_<N>`. - Volume: `postgres_data`. Health check: `pg_isready`. ### redis (Redis Alpine) - Cache and job-queue backend at `redis:6379`. - One DB index per instance (`<N>`); launched with `--databases 100`. - Health check: `redis-cli ping`. ### minio (S3-compatible storage) - File storage at `minio:9000` (container) or `localhost:9000` (host). - Console at `localhost:9001` with credentials `polar-development` / `polar123456789`. - Per-instance buckets: `polar-s3-<N>`, `polar-s3-public-<N>`. - Volume: `minio_data`. ### tinybird - Analytics engine at `tinybird:7181` (admin `7182`). Token is auto-discovered from the running container on api startup. ## Application services (project `polar-app-<N>`) ### api (FastAPI backend) - `python:3.14.6-slim` + uvicorn, hot-reload on. - Host port: `8000` (instance 0) or `8100+N`. - Healthcheck: `curl /healthz` (generous `start_period` covers first-boot sync + migrations + seed). - Startup: `uv sync`, build email templates, bootstrap DB/buckets, run migrations, load seed data on first run. ### worker (background jobs) - Same image as api. No host port. - Dramatiq with the priority queues (`high_priority`, `medium_priority`, `low_priority`), hot-reload on. - Waits for api before starting. ### web (Next.js frontend) - `node:22-slim` + Turbopack, hot-reload on. - Host port: `3000` (instance 0) or `3100+N`. Memory limit: 6 GB. - Healthcheck via Node's built-in `fetch` (the image has no curl/wget). - Waits for api to be **healthy** before starting (it proxies SSR to api). ## Optional monitoring (project `polar-shared`, `--monitoring`) - **prometheus** — metrics, 1-day retention, at `prometheus:9090` (no host port). - **grafana** — dashboards at `grafana:3000` internally, login `polar` / `polar` (no host port; port-forward if you need the UI). ## Container dependencies ``` minio-setup → minio (healthy) api → db, redis, minio-setup worker → api (started) web → api (healthy) grafana → prometheus ``` ## Volume persistence | Volume | Purpose | |--------|---------| | postgres_data | Database (shared) | | minio_data | Files (shared) | | server_uv_cache | Python package cache | | api_venv / worker_venv | Per-service virtualenv | | pnpm_store | Node package store | | web_node_modules | Frontend deps | | web_next_cache | Build cache | ## Networking App containers join a per-instance `default` bridge plus `polar-shared`. Infra is addressed by name (`db:5432`, `redis:6379`, `minio:9000`, `api:8000`). Web stays off `polar-shared` so `http://api:8000` resolves to *this* instance's api. -
shell-and-workflows.md 2.6 KB
--- title: Shell Access and Common Workflows category: Operations tags: shell, exec, workflows, testing --- # Shell Access and Common Workflows ## Shell into a container ```bash dev docker shell api # Python env (api) dev docker shell worker # Python env (worker) dev docker shell web # Node env dev docker shell db # postgres container (shared) ``` For one-off commands without an interactive shell, use `exec`: ```bash dev docker exec api uv run alembic current dev docker exec db psql -U polar -d polar_dev_<N> -c "SELECT 1" dev docker exec redis redis-cli -n <N> dbsize ``` `exec`/`shell` auto-route by service name: app services hit this instance's `polar-app-<N>` project, infra services hit `polar-shared`. ## Useful in-container commands **api / worker (Python):** ```bash uv run alembic upgrade head # run migrations uv run alembic revision --autogenerate -m "message" # create a migration uv run alembic current # show current revision ``` (Backend tests are the exception — they don't run in this container; see below.) **web (Node):** ```bash pnpm test pnpm lint ``` **db (PostgreSQL):** the database is per-instance, so pass `polar_dev_<N>`, not `polar`: ```bash psql -U polar -d polar_dev_<N> ``` ## Common workflows **Daily development:** ```bash dev docker up -d --wait # start and wait until serving dev docker ps # confirm status dev docker logs -f api # watch as you work dev docker down # stop when done (data persists) ``` **After a git pull:** hot-reload handles most changes. If deps changed: ```bash dev docker restart api worker web # picks up new deps via startup uv sync / pnpm # only if a Dockerfile or system dep changed: dev docker up -b -d api worker web ``` **Run tests:** Frontend unit tests run in the web container: ```bash dev docker exec web pnpm test ``` Backend tests do **not** run in the `dev docker` api container. The suite's session-wide `empty_test_bucket` fixture hard-requires S3 at `http://127.0.0.1:9000` with `testing`-prefixed buckets, but containers can't reach `localhost:9000` on the host — they use `minio:9000` internally with per-instance `polar-s3-<N>` buckets. Run backend tests on the host with the standard setup in `server/AGENTS.md` (`uv run task test`). **Database operations:** ```bash dev docker exec api uv run alembic upgrade head dev docker exec api uv run alembic downgrade -1 dev docker exec db psql -U polar -d polar_dev_<N> ``` Find `<N>` (and the real ports) for the current worktree with `dev docker ports`. -
start-environment.md 3 KB
--- title: Starting the Local Environment category: Operations tags: docker, start, development --- # Starting the Local Environment `dev docker up` starts shared infra (if it isn't already running) plus this worktree's app stack. It **defaults to detached** (`-d` is on by default), so plain `dev docker up` returns once containers are created. ## Basic commands **Start in background (the default):** ```bash dev docker up -d ``` **Start and block until app services are healthy:** ```bash dev docker up -d --wait ``` `--wait` returns only once api answers `/healthz` and web responds. Prefer it in scripts and tooling so "up finished" means "actually serving" rather than "the container was created" — on first boot the app keeps compiling and migrating for a while after the container starts. **Start in the foreground and stream logs:** ```bash dev docker up --no-detach ``` Shared infra still starts detached; only the app stack is attached, so Ctrl+C stops the app stack. **Start specific services:** ```bash dev docker up -d api # api (+ shared infra) dev docker up -d web # web (+ shared infra) dev docker up -d api worker # api and worker ``` ## Options | Flag | Description | | ----------------- | ---------------------------------------------------- | | `-d` / `--detach` | Detached / background (default) | | `--no-detach` | Foreground; stream app logs until you stop it | | `--wait` | Block until app services are healthy (detached only) | | `-b` / `--build` | Rebuild images before starting | | `--pull` | Refresh base images before building (see below) | | `--monitoring` | Include Prometheus and Grafana in shared infra | | `-i N` | Target instance N explicitly (usually auto-detected) | ## Rebuilding with fresh bases ```bash dev docker up -b --pull -d ``` `-b` rebuilds the images, and `--pull` refreshes the base images first. Use `--pull` after a `.python-version` bump or when a rebuild alone still boots the old interpreter — a cached `FROM` layer can otherwise pin you to a stale base. See troubleshooting for the "No interpreter found for Python X" symptom. ## First-time startup First run is slow because it does real work inside the containers: 1. Build the api/web images 2. `uv sync` (api/worker) and `pnpm install` (web) — several minutes 3. Bootstrap the per-instance DB and MinIO buckets 4. Run migrations and load seed data 5. Services become healthy `dev docker up -d --wait` is the cleanest way to wait this out. ## Finding the URLs Ports are per-instance, so don't assume 3000/8000. Ask: ```bash dev docker ports # human-readable dev docker ports --json # for tooling ``` For instance 0 the app is at http://localhost:3000 (web) and http://localhost:8000 (api, docs at `/docs`). MinIO exposes ports 9000 (API) and 9001 (console) on localhost; db and redis have no host port — reach them with `dev docker exec <service> ...`. -
stop-environment.md 1.6 KB
--- title: Stopping the Local Environment category: Operations tags: docker, stop, cleanup --- # Stopping the Local Environment Commands act on **this instance's app stack** by default; the shared infra (postgres/redis/minio/tinybird) keeps running so other worktrees aren't disrupted. Reach for the shared stack explicitly only when you mean to. ## Stop services **Stop this instance's app stack (keeps data + shared infra):** ```bash dev docker down ``` **Stop the app stack and the shared infra too:** ```bash dev docker down --all ``` **Stop a specific instance:** ```bash dev docker down -i 1 ``` ## Cleanup (destructive) **Reset this instance** — removes its api/worker/web containers and their build/cache volumes. Shared infra and its data are left intact: ```bash dev docker cleanup -f ``` **Wipe everything shared** — this destroys postgres data, MinIO objects, Tinybird events, and prometheus/grafana state for **every** instance on the machine: ```bash dev docker cleanup --all -f ``` Use per-instance cleanup for a fresh app stack; use `--all` only when you truly want to reset the machine-wide data. To drop just one instance's DB/buckets without touching others, delete its worktree and run `dev docker prune`. ## Restart vs stop/start **Restart (keeps containers, fastest):** ```bash dev docker restart # all app services dev docker restart api # one service ``` **Stop/start (recreates containers):** ```bash dev docker down dev docker up -d ``` Prefer `restart` for quick changes. Recreate when you've changed Docker config, environment variables, or a container is wedged. -
troubleshooting.md 6 KB
--- title: Troubleshooting Common Issues category: Debugging tags: troubleshooting, errors, fixes --- # Troubleshooting Common Issues ## Service Won't Start **Check if ports are in use:** ```bash lsof -i :8000 # API port lsof -i :3000 # Web port lsof -i :5432 # Database port ``` **Verify Docker is running:** ```bash docker info ``` **Check container logs:** ```bash dev docker logs api dev docker logs web ``` **Try stop and restart:** ```bash dev docker down dev docker up -d ``` ## Docker Daemon Not Running `dev docker up` preflights the daemon and prints a friendly message if it's down. If you see it, start Docker (OrbStack or Docker Desktop) and retry. A raw `docker.sock: no such file or directory` from another command means the same thing. ## `No interpreter found for Python 3.14.x` (stale base image) The api container exits during the JWKS/`uv sync` step with something like: ``` error: No interpreter found for Python 3.14.6 in managed installations or search path ``` This is a **stale base image**: the cached api image ships an older Python patch than `server/.python-version` requires, and a plain rebuild reuses the cached `FROM` layer. Refresh the bases and rebuild: ```bash dev docker up -b --pull -d ``` `--pull` re-fetches `python:3.14.x-slim` and `uv` so the rebuilt image satisfies the pin. (The Dockerfile pins the patch to keep this rare, but a `.python-version` bump can still outrun a cached image.) ## First boot fails cloning a git dependency `uv sync` clones a git dependency (the dramatiq fork) over the network, and Docker's embedded DNS can flap transiently: ``` failed to fetch commit ... Could not resolve host: github.com ``` Startup now retries `uv sync` a few times, so this usually self-heals. If the container still exited, just restart it — the retry runs again with a fresh resolver: ```bash dev docker up -d api worker ``` ## Database Connection Failed **Wait for health check (up to 40 seconds on first start)** **Check db container:** ```bash dev docker ps dev docker logs db ``` **Verify database is healthy:** ```bash # Each instance has its own database: polar_dev_<instance-number> dev docker exec db psql -U polar -d polar_dev_<N> -c "SELECT 1" ``` Shared infra (db/redis/minio) is on the `polar-shared` Docker network with no host port — reach it through `dev docker exec` or `docker exec polar-shared-<svc>-1`. ## Hot-Reload Not Working **Check file mounting:** ```bash dev docker shell api ls -la /app/server/polar/ ``` **Restart the service:** ```bash dev docker restart api ``` **If still broken, rebuild:** ```bash dev docker build api dev docker restart api ``` ## Out of Memory **Check Docker memory settings** (should be 8GB+) **Stop unused instances:** ```bash dev docker down -i 1 dev docker down -i 2 ``` **Clean up Docker:** ```bash docker system prune ``` ### `ERR_PNPM_ENOMEM` on first `dev docker up` On a fresh worktree the api container (building the email renderer) and the web container (installing frontend deps) can both run `pnpm install` at the same time and OOM. Symptom in `docker logs polar-app-<N>-api-1`: ``` ERR_PNPM_ENOMEM ENOMEM: not enough memory, copyfile ... ``` `docker ps` then shows api/web with `Exited (1)` while worker is still `Up`. **Fix — restart the failed containers, pnpm resumes from its cache:** ```bash docker start polar-app-<N>-api-1 polar-app-<N>-web-1 ``` Wait for `/healthz` on the API port (printed by `dev docker up`) to come up before continuing. Bumping Docker Desktop's memory above 8 GB or starting services one at a time (`dev docker up -d api`, then `web`) also avoids the clash. ## MinIO/S3 Issues Shared MinIO exposes ports 9000 (API) and 9001 (console) on localhost. Access the console at http://localhost:9001 with credentials `polar-development` / `polar123456789`. **Check minio-setup logs:** ```bash dev docker logs minio-setup ``` **List this instance's buckets:** ```bash dev docker exec minio mc alias set local http://localhost:9000 \ polar-development polar123456789 dev docker exec minio mc ls local ``` Buckets are per-instance: `polar-s3-<N>` and `polar-s3-public-<N>`. ## Frontend Build Errors **Clear Next.js cache:** ```bash dev docker shell web rm -rf .next exit dev docker restart web ``` **Reinstall dependencies:** ```bash dev docker shell web pnpm install exit dev docker restart web ``` ## Migration Issues **Check current migration state:** ```bash dev docker shell api uv run alembic current ``` **Run pending migrations:** ```bash uv run alembic upgrade head ``` **Rollback if needed:** ```bash uv run alembic downgrade -1 ``` ## Stale Connections After Shared DB Recycle If `polar-shared-db-1` was recreated (e.g. you ran `dev docker down` on the shared stack, or it was replaced by an unrelated `docker compose` run), the running api/worker still hold connections to the old container and surface errors like: ``` asyncpg.exceptions._base.InterfaceError: connection is closed sqlalchemy.dialects.postgresql.asyncpg.InterfaceError ``` **Fix — restart api and worker so the pool reconnects:** ```bash docker restart polar-app-<N>-api-1 polar-app-<N>-worker-1 ``` ## Don't Mix `dev docker` and Bare `docker compose` `dev docker` runs the shared infra under the project name `polar-shared` on the `polar-shared` network. Running `cd server && docker compose up` from the same checkout creates a parallel stack on `server_default` with `server-` prefixed containers. They don't conflict by name, but: they double the memory footprint, `docker ps` shows two of everything, and a later `docker compose down` on one stack will leave the other half running with broken cross-network references. Pick one. For everything in this skill, prefer `dev docker`. ## Complete Reset **When all else fails:** ```bash dev docker cleanup -f dev docker up -b -d ``` This removes all data and rebuilds from scratch. ## Getting Help 1. Check logs: `dev docker logs` 2. Check status: `dev docker ps` 3. Check Docker: `docker info` 4. Try restart: `dev docker restart` 5. Try cleanup: `dev docker cleanup` -
view-logs.md 1.9 KB
--- title: Viewing Service Logs category: Debugging tags: logs, debugging, troubleshooting --- # Viewing Service Logs `dev docker logs` **follows by default** (`-f` is on). It auto-routes by service name: app services (api/worker/web) come from this instance's `polar-app-<N>` project, and infra services (db/redis/minio/...) from `polar-shared`. ## Commands **Follow all app logs (the default):** ```bash dev docker logs ``` **Print current logs and exit (don't follow):** ```bash dev docker logs --no-follow dev docker logs --no-follow api ``` Use `--no-follow` in scripts or when you just want a snapshot — otherwise the command blocks streaming. (This maps to a foreground `docker compose logs`.) **Specific service logs:** ```bash dev docker logs api dev docker logs worker dev docker logs web dev docker logs db # auto-routed to polar-shared dev docker logs redis dev docker logs minio ``` **Follow a specific service:** ```bash dev docker logs -f api ``` **Instance-specific logs:** ```bash dev docker logs -i 1 api ``` ## Log Interpretation ### API Logs **Successful request:** ``` INFO: 127.0.0.1:54321 - "GET /api/v1/users HTTP/1.1" 200 ``` **Error:** ``` ERROR: Exception in endpoint Traceback (most recent call last): ... ``` ### Worker Logs **Task started:** ``` [dramatiq.MainProcess] Task started: polar.tasks.example:process ``` **Task completed:** ``` [dramatiq.MainProcess] Task completed in 0.123s ``` ### Web Logs **Page compiled:** ``` ✓ Compiled /dashboard in 234ms ``` **Error:** ``` Error: Cannot find module 'xxx' ``` ## Debugging Tips 1. **Follow API logs during development:** ```bash dev docker logs -f api ``` 2. **Check worker for background job issues:** ```bash dev docker logs -f worker ``` 3. **Database issues - check db:** ```bash dev docker logs db ``` 4. **Startup issues - check all:** ```bash dev docker logs ```
-
-
SKILL.md 5.4 KB
--- name: polar-local-environment description: "This skill should be used when setting up or managing Polar local development environment with Docker." license: MIT metadata: author: polar version: "1.1.0" --- # Local Environment Skill Helps manage the Polar local development environment through the `dev docker` CLI. Use it to start, stop, debug, or reason about the local stack. ## The two-part model `dev docker` deliberately splits the stack so many worktrees can share one set of heavy infra: - **Shared infra** — one copy per machine, Docker project `polar-shared`: postgres, redis, minio, tinybird, and optional prometheus/grafana. Postgres and redis publish no host ports; MinIO exposes 9000/9001 for browser uploads. Use `dev docker exec <service> ...` for services without host ports. - **Per-instance app stack** — one per worktree, project `polar-app-<N>`: api, worker, web. Only **api and web** publish host ports, offset per instance so worktrees don't collide. Knowing this prevents the most common confusion: there is no `localhost:5432` for the database (it lives in the shared stack and is reached through `dev docker exec db ...`). MinIO does expose ports 9000/9001 for browser uploads and console access. ## Instance auto-detection `dev docker` auto-detects the instance for the current worktree, so `-i` is rarely needed. Priority: 1. `POLAR_DOCKER_INSTANCE` pinned in `dev/docker/.env.docker` (`dev docker set-instance N`) 2. `CONDUCTOR_PORT` env var → `(port - 55000) / 10 + 1` 3. The cross-worktree registry (`~/.config/polar/docker-instances.json`) 4. Otherwise the lowest free number, then registered Run `dev docker ports` to see the resolved instance and its URLs (add `--json` for tooling). To wire this worktree into Claude Code's preview, run `dev docker launch-json`, which writes a per-instance `.claude/launch.json` with the correct ports (it's gitignored, so regenerate after `set-instance`). ## When to use - Start / stop / restart the local environment - View logs or debug a service that won't come up - Run several isolated worktree instances in parallel - Understand the service architecture or find a service's real port - Diagnose container or first-boot errors ## Quick reference | Task | Command | |------|---------| | Start full stack (background) | `dev docker up -d` | | Start and block until healthy | `dev docker up -d --wait` | | Start in foreground (stream logs) | `dev docker up --no-detach` | | Rebuild with fresh base images | `dev docker up -b --pull -d` | | Show this instance's ports/URLs | `dev docker ports` (`--json` for tooling) | | Write Claude Code preview config | `dev docker launch-json` | | Stop app stack | `dev docker down` | | Stop app **and** shared infra | `dev docker down --all` | | Follow logs | `dev docker logs -f [service]` | | Print logs and exit | `dev docker logs --no-follow [service]` | | Status | `dev docker ps` | | Restart a service | `dev docker restart <service>` | | Shell into a service | `dev docker shell <service>` | | One-off command in a service | `dev docker exec <service> <cmd>` | | Reset this instance | `dev docker cleanup -f` | | Wipe ALL shared data | `dev docker cleanup --all -f` | | List every instance | `dev docker list` | | With monitoring | `dev docker up --monitoring -d` | ## Services | Service | Project | Host port (instance 0 / N) | Notes | |---------|---------|----------------------------|-------| | api | `polar-app-<N>` | 8000 / 8100+N | FastAPI; `/healthz` healthcheck | | web | `polar-app-<N>` | 3000 / 3100+N | Next.js; healthchecked | | worker | `polar-app-<N>` | none | Background jobs | | db | `polar-shared` | none (`exec`) | PostgreSQL; DB `polar_dev_<N>` | | redis | `polar-shared` | none (`exec`) | Redis DB index = N | | minio | `polar-shared` | 9000, 9001 | S3; buckets `polar-s3-<N>`; console at 9001 | | tinybird | `polar-shared` | none (`exec`) | Analytics | | prometheus / grafana | `polar-shared` | none (`exec`) | `--monitoring` only | Discover the exact host ports for the current worktree with `dev docker ports`. ## Instance port mapping Only api and web get host ports: `Port = Base + Instance` (Base 8100 for api, 3100 for web) for instances 1–99. Instance 0 uses the legacy `8000` / `3000`. | Instance | API | Web | |----------|-----|-----| | 0 | 8000 | 3000 | | 1 | 8101 | 3101 | | 2 | 8102 | 3102 | | 5 | 8105 | 3105 | Everything else is per-instance but not on a host port: database `polar_dev_<N>`, redis DB index `<N>`, buckets `polar-s3-<N>` / `polar-s3-public-<N>`. Reach them via `dev docker exec <service>` or `docker exec polar-shared-<service>-1`. ## Rules index | Rule | Category | Description | |------|----------|-------------| | [service-architecture](rules/service-architecture.md) | Reference | Service details, ports, healthchecks | | [start-environment](rules/start-environment.md) | Operations | Starting the stack (flags, `--wait`, `--pull`) | | [stop-environment](rules/stop-environment.md) | Operations | Stopping and cleanup (app vs shared) | | [manage-instances](rules/manage-instances.md) | Operations | Parallel worktree instances | | [view-logs](rules/view-logs.md) | Debugging | Viewing service logs | | [shell-and-workflows](rules/shell-and-workflows.md) | Operations | Shell access and common dev workflows | | [troubleshooting](rules/troubleshooting.md) | Debugging | Common errors and fixes | | [payment-testing](rules/payment-testing.md) | Operations | Login codes, Stripe webhooks, backoffice |
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.