Тимчасовий захист в Іспанії: офіційні локації та досвід спільноти.
Translation pending
SocialTypeScript · PLpgSQLGitHub @OrestPolusynOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
Mobile-first Next.js app (App Router, TypeScript strict, Supabase, Tailwind),
usable both as a normal website and as a Telegram Mini App, letting Ukrainians
in Spain search official temporary-protection locations by province and see
dated community reports of what documents each office actually asked for.
See docs/SPEC.md for the full product/domain specification this app
implements, and docs/BOTFATHER.md for the Telegram bot/Mini App setup
checklist.Read the full README ↗Mobile-first Next.js app (App Router, TypeScript strict, Supabase, Tailwind), usable both as a normal website and as a Telegram Mini App, letting Ukrainians in Spain search official temporary-protection locations by province and see dated community reports of what documents each office actually asked for.
See docs/SPEC.md for the full product/domain specification this app
implements, and docs/BOTFATHER.md for the Telegram bot/Mini App setup
checklist.
npm install
.env.example to .env.local and fill in:
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY,
SUPABASE_SERVICE_ROLE_KEY — from Project Settings → API Keys
(Supabase is retiring the old "anon"/"service_role" JWT pair for
"Publishable"/"Secret" keys — see the comment in .env.example for
which goes where; the variable names here don't change either way).supabase/migrations/0001_*.sql through
0008_*.sql) — via the Supabase CLI (supabase db push, once the project
is linked) or by pasting each file into the SQL Editor in the dashboard,
in filename order.seed/locations.csv:
SUPABASE_URL=<project-url> SUPABASE_SERVICE_ROLE_KEY=<service-role-key> npm run seed
This is idempotent (safe to re-run against an unchanged database — see the
caveat in scripts/seed.ts's header about re-running after moderation).
Re-running after the official list changes also hides the locations it
dropped; they keep their reports and can be re-published by a moderator.Follow docs/BOTFATHER.md, then fill in TELEGRAM_BOT_TOKEN,
NEXT_PUBLIC_TELEGRAM_BOT_USERNAME, NEXT_PUBLIC_TELEGRAM_MINI_APP_NAME in
.env.local.
NEXT_PUBLIC_SITE_URL — your dev/prod URL.OFFICIAL_INFO_URL — a real link to official government information;
never invent this.PRIVACY_CONTROLLER_NAME, PRIVACY_CONTACT_EMAIL — the real data
controller's name and contact email. The production build fails if
either is unset (see src/lib/config.ts getPrivacyConfig()); in
development, /privacy shows a "TODO: not configured" banner instead.DEV_LOGIN_ENABLED — true to enable GET /api/auth/dev?user=1|2 for
testing without a real Telegram login (only takes effect outside
production regardless of this flag — see "Dev login" below).npm run dev
Open http://localhost:3000.
This was built and tested in a sandbox with no Docker daemon and no way to
fetch the PostgREST/GoTrue binaries the Supabase CLI's supabase start needs
— npx supabase start fails there with a Docker-socket connection error.
Everything that only needs Postgres itself (not the full Supabase stack) was
instead verified against a plain local PostgreSQL 16 instance:
createdb tpd_test
psql -d tpd_test -f supabase/tests/00_supabase_stub.sql # NEVER run against a real Supabase project — see its header
for f in supabase/migrations/*.sql; do psql -d tpd_test -v ON_ERROR_STOP=1 -f "$f"; done
psql -d tpd_test -v ON_ERROR_STOP=1 -f supabase/tests/01_load_fixture_seed.sql
00_supabase_stub.sql provides a minimal auth.users table, auth.uid()
function and anon/authenticated roles — just enough to exercise RLS and
the matching function with real SQL, without GoTrue/PostgREST. This is how
every acceptance criterion under "Data", "Search and matching", "Reports and
moderation" and most of "Security and privacy" in docs/SPEC.md was actually
verified (see the milestone commits for specifics, including two real bugs
this caught: flags_promote_to_flagged() needing SECURITY DEFINER, and a
missing location_procedures INSERT grant).
What this setup cannot verify: anything requiring real GoTrue-issued
JWTs/sessions or a live HTTP PostgREST endpoint — i.e. npm run dev actually
rendering pages against real data, and the Telegram auth bridge's
generateLink/verifyOtp exchange end-to-end. Those need either
Docker + the Supabase CLI, or a real hosted Supabase project. If you have
either, prefer supabase start && supabase db reset over the manual steps
above — supabase db reset applies supabase/migrations/ automatically.
npm run lint # eslint (Next.js config)
npm run build # production build; also where "/" client-JS budget is enforced
npm test # vitest: pure-function/unit tests, no database needed
npm run test:db # vitest: DB integration tests — needs TEST_DATABASE_URL
# (defaults to the Supabase CLI's local port 54322;
# point it at the plain-Postgres setup above instead
# with e.g. TEST_DATABASE_URL=postgresql://user:[email protected]:5432/tpd_test)
npm run report:home-bundle # prints "/"'s gzipped client-JS size after a build
.env.example in Project Settings → Environment
Variables (for Production and Preview, if you want preview
deployments to work) — SUPABASE_SERVICE_ROLE_KEY and
TELEGRAM_BOT_TOKEN must be added as server-only (never exposed to the
client; Vercel does this automatically for vars without the
NEXT_PUBLIC_ prefix).NEXT_PUBLIC_SITE_URL to the production domain, then update the
Mini App's Web App URL and the Login Widget's domain in @BotFather to
match (docs/BOTFATHER.md steps 2 and 5).PRIVACY_CONTROLLER_NAME/PRIVACY_CONTACT_EMAIL being unset will
fail the build here, by design.See docs/BOTFATHER.md — bot creation, Mini App registration, menu button,
/start, and linking the Login Widget's domain.
There is no admin UI in this app (out of scope, per docs/SPEC.md) —
everything below happens in the Supabase dashboard's Table Editor / SQL
Editor.
locations where moderation_status = 'pending'):
either a conflict seed row needing a phone call to verify (see
seed/VERIFICATION.md), or a user submission (verification_status = 'user_submitted'). Check it, then set moderation_status = 'published'
(or 'rejected').location_suggestions where status = 'pending'): compare current_value (a snapshot from submit time) against
proposed_value. If you accept it, manually update the corresponding
column on the locations row, then set the suggestion's status to
'approved' (this is a manual two-step edit — there is no auto-apply, per
spec: "no import, bulk-insert... path exists for any role, including
moderators").moderation_status = 'flagged', reached
automatically at 3 distinct flaggers): review, then set to 'published'
(restore) or 'hidden'. Never gets there automatically from 'hidden'.policy_changes once a change's
effective_date is confirmed from an official source — never invent a
date. This immediately affects the matching function's "До зміни правил"
labelling and default counts for older reports (see
supabase/migrations/0007_matching.sql). The military-obligation
requirement mentioned in content/legal-notice.uk.md is exactly the kind
of change this table exists for.update profiles set role = 'moderator' where id = '<uuid>';. There is no
self-service path to this role.Cited inline in the relevant source files; collected here per the build prompt's requirement.
Telegram (validation algorithms — src/lib/telegram/):
initData validation: https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-appSupabase (the Telegram→Supabase-session auth bridge — src/lib/telegram/authBridge.ts):
admin.generateLink: https://supabase.com/docs/reference/javascript/auth-admin-generatelinkverifyOtp: https://supabase.com/docs/reference/javascript/auth-verifyotp@supabase/ssr cookie pattern) — src/lib/supabase/server.ts, src/proxy.ts: https://supabase.com/docs/guides/auth/server-side/nextjsNetwork access to core.telegram.org and supabase.com was blocked by this
sandbox's egress proxy, so these algorithms/APIs were corroborated via
multiple independent secondary sources (community write-ups reproducing the
official pseudocode verbatim) rather than a direct fetch of the pages above,
and the exact verifyOtp parameter shape was additionally checked directly
against the installed @supabase/auth-js TypeScript types (see the comment
in authBridge.ts) rather than trusted from a blog post. Before shipping
this to production, fetch both doc pages directly and diff against the
algorithms implemented here — they are stable, well-known algorithms, but
this was not independently re-verified against the live pages in this
environment.
npm run dev against a live Supabase project (no
Docker/Supabase CLI, no external Supabase project credentials in this
sandbox) — see "Local development" above for exactly what was and wasn't
verified.generateLink/verifyOtp exchange was checked
against the installed SDK's TypeScript types and is expected to work per
the SDK's documented contract, but was not exercised against a real
Supabase Auth server (needs a real project + a real or synthetic Telegram
login).