PollApp is a responsive Angular survey application for creating polls, collecting anonymous votes, and watching aggregate results update live through Supabase.
Production: pollapp.naranjo.io
GitHub Pages: obo-wan.github.io/PollApp
|
|
| Create a survey | Vote and follow live results |
The five functional user stories from the Poll-App project checklist are implemented:
| User story | Implementation |
|---|---|
| Ending soon | Active surveys are ordered chronologically by their deadline. |
| Survey overview | Active and past surveys can be browsed and filtered by category. |
| Create survey | The form supports questions, answers, categories, optional deadlines, and validation. |
| Survey details | Published surveys show their questions, answer options, metadata, and current results. |
| Voting and results | Anonymous votes persist transactionally and aggregate results update through Supabase Realtime. |
- Angular 22 standalone components with strict TypeScript configuration.
- Responsive desktop, tablet, and mobile layouts based on the supplied Figma designs.
- Supabase Postgres migrations, row-level security, transactional RPCs, seed data, and pgTAP tests.
- Browser-safe runtime configuration for local development, netcup, and GitHub Pages deployment.
- Fixture fallback for unavailable reads without disguising failed configured writes.
- Hash-based routing so survey links remain reload-safe on static hosting.
- Vitest unit tests and Playwright browser coverage for the principal workflows and viewports.
Start the local Supabase stack and apply its seed data:
npm run supabase:start
npm run supabase:reset
npm startnpm start writes a browser-safe runtime configuration from supabase status -o env, then
starts Angular. Open http://localhost:4200/. If Supabase becomes unavailable, the application
keeps working with fixture surveys and displays a fallback notice.
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
ng generate component component-nameFor a complete list of available schematics (such as components, directives, or pipes), run:
ng generate --helpTo build the project run:
ng buildThis will compile your project and store the build artifacts in the dist/ directory. By default, the production build optimizes your application for performance and speed.
GitHub Pages uses hash-based Angular routes, such as
https://obo-wan.github.io/PollApp/#/surveys/1. The fragment stays in the browser, so opening or
refreshing a survey requests the /PollApp/ root document with HTTP 200 instead of requesting a
nested path that GitHub Pages cannot rewrite. Local development uses the same route format, such as
http://localhost:4200/#/surveys/1.
The GitHub Pages workflow generates supabase-config.json during the production build. Configure
these repository variables under Settings > Secrets and variables > Actions > Variables before
deploying:
| Variable | Value |
|---|---|
POLLAPP_SUPABASE_URL |
Hosted project URL, such as https://ref.supabase.co |
POLLAPP_SUPABASE_PUBLISHABLE_KEY |
Browser-safe sb_publishable_... or legacy anon key |
The generated file is copied into the GitHub Pages artifact and remains Git-ignored locally. The configuration writer rejects non-HTTP URLs and keys that are not browser-safe, so a missing or unsafe configuration fails the deployment instead of publishing a misconfigured application.
netcup uses the same hash-based routes and hosted Supabase project as GitHub Pages. A survey URL
such as https://pollapp.naranjo.io/#/surveys/1 therefore remains refresh-safe while the application
is hosted at the domain root.
Provide POLLAPP_SUPABASE_URL and POLLAPP_SUPABASE_PUBLISHABLE_KEY when creating the netcup
production bundle:
npm run build:netcupThe command generates public/supabase-config.json and builds the application with a / base href.
Upload the contents of dist/poll-app/browser/ to the document root
pollapp.naranjo.io/httpdocs using netcup's encrypted SFTP support or the Webhosting Control Panel
file manager.
Never use a secret or service-role key in Angular, GitHub repository variables, build environment
variables, or public/supabase-config.json. Browser access is authorized by the publishable key and
constrained by the database grants and row-level security policies in supabase/migrations/.
Run formatting, unit tests, and an Angular build together:
npm run verifyRun the complete Playwright suite:
npm run test:e2eThe Playwright suite covers the principal survey workflows and responsive viewports.
The database contract lives in supabase/. It includes:
- relational survey, question, answer, vote, and result tables;
- transactional functions for creating surveys and submitting votes;
- anonymous read policies with writes restricted to those functions;
- seed data matching the current Angular survey fixtures.
Angular reads surveys from the configured Data API through @supabase/supabase-js, with fixture
fallback when reads are unavailable. When Supabase is configured, survey creation and vote
submission use the transactional database functions and never fall back to fixture writes. Vote
submission uses a stable UUID stored only in the browser for best-effort duplicate prevention; it
does not enable Angular authentication or session persistence.
Configured clients also subscribe to anonymous Realtime updates from the public aggregate
answer_results table, so an open survey result view updates when another browser submits a vote.
To start a clean local database, apply the migrations and seed, and run the database tests:
npm run supabase:verifyDocker must be installed and running. See supabase/README.md for local and hosted-project setup.
Run the focused browser integration after the local stack has started:
npm run test:e2e:supabaseFor more information on using the Angular CLI, including detailed command references, visit the Angular CLI Overview and Command Reference page.



