Full process template for citizen initiative campaign, from digital signatures collection to PDF document rendering for legislative submission.
Table of contents
- Ready to use campaign static website (Astro, Svelte, Tailwind and DaisyUI)
- An online form with signature pad
- Signatures counter, from both offline and online channel
- Support offline sign locations list
- Privacy policy template
- GitHub Action's Workflow file for build and deploy to Github Pages
- Database configuration (Firebase, and Google Sheets with Sheethuahua)
- Firebase rules for spamming protection for online submission
- Firebase emulator with mocked data for local development
- Google Sheets template for human-curated data
- Post-campaign scripts (pdf-lib and Node.js)
- Download online submission signatories' data as CSV files
- Render CSV data on the pdf template for legislative submission
Configuration file is provided, but everything can be customized via code.
Required Node.js v20 or higher with NPM package manager.
npx degit github:wevisdemo/e-initiative-template <project-name>
The template will be downloaded to the project-name
folder.
For online signature submission
- Create a new project in Firebase Console
- Set up Authentication
2.1. Enable "Email/Password" and "Anonymous" sign-in methods.
2.2. Add user and provide email/password for admin account. Then add the same information in local
.env.production
file (create it in the project folder if it does not exist) withADMIN_EMAIL
andADMIN_PASSWORD
keys. 2.3. Copy admin's User UID for the next step. - Set up Firestore Database
3.1 Enable the Firestore
3.2 Copy rules from
firestore.rules
and update admin's UID from the previous step. (Only update rules on the console,firestore.rules
is used by the local emulator) - Obtain Firebase config
3.1 Add a new web app from project settings > General > Your Apps
3.2 Copy
firebaseConfig
as a one-line JSON format and put it inPUBLIC_FIREBASE_CONFIG
of local.env.production
file.
At the end, your .env.production
file should look like this:
PUBLIC_FIREBASE_CONFIG={"apiKey": "???", "authDomain": "???", "projectId": "???", "storageBucket": "???", "messagingSenderId": "???", "appId": "???"}
ADMIN_EMAIL=???
ADMIN_PASSWORD=???
Note: there is a .env.development
with mocked data for working with the Firebase emulator in local development environment. You don't need to change anything there.
For human-curated data, including offline signatures count and voluntary sign locations. Skip this step if your campaign don't need both function.
- Duplicate Google Sheets template. It contain 2 sheets:
- "offline-signature" sheets for recoding offline signature count in each day. Total number is the summation of every row.
- "locations" is the sign location showing in the location page.
- Grant "Viewer" permission to "Anyone with the link" in Share menu
- Obtain Sheets ID from the URL
https://docs.google.com/spreadsheets/d/{sheetsID}/
and add it to thesheets.id
ine-initiative.config.mjs
- (Optional) If you allow anyone to submit a voluntary offline sign location.
4.1. Create a Google Form with fields corresponded to the columns in
locations
sheet. 4.2. In the form response settings, link the form response to your duplicated sheets. A response sheet will be created with each question in the header. 4.2. Rename column header to be likelocations
sheet. Doesn't need to have the same order, but it must corresponded to each question. 4.3 Remove oldlocations
sheet and rename form response sheet to belocations
instead.
Most of the campaign information can be config via e-initiative.config.mjs
. Explanation can be found by hovering at the configuration keys (on JSDoc supported IDE) or the type definition file. Configuration should be update first so that you will know what is not covered and require editing the source code.
- Website content can be directly edited through source code. Index page entry point to get started is
src/pages/index.astro
. - UI components are from either Daisy UI v3 or custom made available in
src/components
. Svelte is mainly used but you can install additional UI Framework integration for Astro - Color theme defined in
e-initiative.config.mjs
is available as a Tailwind class. For VSCode user, Tailwind extension is recommended for Tailwind class auto-completion. - Typography CSS global utility classes are defined in
src/styles/typography.css
and ready to be used. - Design system is corresponded to the Figma
- Don't forget to review the privacy policy in
src/pages/privacy-policy.astro
and remove the "mark" tags (for highlighting) after updating the content.
To start Astro development server and Firebase emulator:
npm run dev
During the development mode, any changes to Firebase will be in local emulator, leaving production database untouched. Mock data will be initialized in Firestore emulator for post-campaign script testing. The .env.development
is used.
To build website for production:
npm run build
Static site will be generated to /dist
and we can preview production build with
npm run preview
Note that production build will use .env.production
and the real Firebase, not emulator.
Since Astro use Static Site Generation (SSG), no data from Firebase and Google Sheets will be updated after the build. So we recommended to use CI/CD tools that support schedule deployment such as Github Actions. Then we can periodically re-build and re-deploy in a given period. Don't forget to add all the production environment variables to the CI/CD.
Template also include GitHub Action's workflow file .github/workflows/demo.yaml
. Please remove it before pushing to GitHub if you don't want to use it. But if you do, don't forget to add all the production environment variables as a repository secrets and remove PUBLIC_DEMO_MODE
env from the Build with Astro step.
Your PDF output template might not have the same field value/position as our given template. Before using the thoudsand of production records, we recommend testing with one record of mock data first.
To get mock data (Firebase emulator must be running from dev
or dev:firebase
command):
npm run download:local
Output CSV files will be generated to /out
directory: one version with base64 signature data, one version without it. Then start the renderer in watch mode:
npm run render:watch
The output PDF files will be re-generated to /out
directory everytime any file has changed. Keep adjusting the renderer
config in e-initiative.config.mjs
until the output PDF looks pretty.
First, download the production signatories' data in CSV format (duplicated or invalid records will be filtered out):
npm run download:prod
Then, render to the PDF files:
npm run render
Both CSV and PDF files will be generated to /out
directory, replacing existing data if exist (eg. from mock data).
Citizens have the rights to propose a law draft to the parliament, when they can gather enough signatures (more about Thailand legislative process). The initiative leader usually follow this pattern:
-
Pre-campaign
- Create a law draft
- Design campaign content and activities
-
Campaign
- Promote the initiative
- Collect citizen signatures through offline/online channel
-
Post campaign
- Submit the draft together with all the signatures to the parliament
This project is licensed under Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) with WeVis Ltd. and Punch Up Ltd. as licensors.