Repository - Docker image - Development/bug tracker
A public event pinboard webapp for your local community, meant to be even lighter on the client devices than on the server!
- To get this project up and running, you can view How-to
- For the design decision behind this project, see Explanation
- For technical info, see Reference
Note: this is - at the point of writing - an application meant for small scale deployments. Please ensure you read Security Considerations
Recommended for: production
Pre-requirements: Docker, Docker Compose
- Create
docker-compose.yml
with the following content:# docker-compose.yml services: community-pinboard: # Pull the Docker image from https://hub.docker.com/r/denperidge/community-pinboard image: denperidge/community-pinboard:latest volumes: - ./data/:/app/data # Mount data directory in ./data ports: - 3000:3000 # Expose port 3000 # Optionally, load environment variables from .env env_file: - path: .env required: false
- Optionally, create a
.env
file to configure environment variables - Run
docker compose up --detach
You can now access the server from localhost:3000
, and any pins & uploads in the data/
directory
Recommended for: production
Pre-requirements: Docker
# Pull & run image
docker run -p 3000:3000 denperidge/community-pinboard:latest
You can now access the server from localhost:3000
Note: this example does not automatically bind ./data to /app/data
Recommended for: development
Pre-requirements: Node.js, Yarn
# Clone the repository, navigate to it and install dependencies
git clone https://github.com/Denperidge/community-pinboard.git
cd community-pinboard
yarn install
yarn build # Build to dist/
yarn prod # Run from dist/
You can now access the server from localhost:3000
, and any pins & uploads in the data/
directory
Alternative commands:
yarn dev
for live-reload developmentyarn test
to run tests (note: see test timezone setting)
Check the other scripts defined in package.json
Recommended for: development
Pre-requirements: Docker
# Clone the repository & navigate to it
git clone https://github.com/Denperidge/community-pinboard.git
cd community-pinboard
docker build -t community-pinboard .
# Run image
docker run -p 3000:3000 community-pinboard
You can now access the server from localhost:3000
Note: this example does not automatically bind ./data to /app/data
Recommended for: development
# Clone the repository & navigate to it
git clone https://github.com/Denperidge/community-pinboard.git
cd community-pinboard
# Build and run image
docker compose up --build
You can now access the server from localhost:3000
, and any pins & uploads in the data/
directory
For customisation, please set the environment variables in your shell, docker-compose or a .env file in the root directory (the same directory this file, README.md is in)
For all configuration options, please refer to Reference: Environment variables.
This application was built to replace fragmented organising through multiple Facebook organisations, Discord servers and Whatsapp pinned messages. This means that by design, the systems built here have to go against this. Below are some of what I have found to be failings of the above tactics
- Non-account-based: Making new accounts feels like second nature to a good portion of the internets users, but it is a hassle, especially for those with less technological skills. Whatsapp circumvented this by using phone numbers, but it still requires an install, and it's still a product of Meta (a company known for an intrinsic disrespect to the privacy of its users). If authentication becomes an element, something simple should be used during pin creation/editing, but a full login and registering system is out of scope.
- Lightweight: Some apps like Messenger, Facebook and Discord or even some websites have forgotten that having your mobile phone isn't sending 500 requests and 20 animations simultaneously may slow down its performance. This website should be as streamlined as possible, and requires as little javascript as possible. All the heavy lifting - if any - should be done on the server side.
- Easy setup & administration: While you might need some technological know-how to get it Community Pinboard up and running at first, the server side is kept intentionally compact. The dependencies and devDepedencies in package.json should be split to ensure that the production version does not get overbloated. The decision to use a simple file-based hierarchy is also in support of this, so that file-based management can be done in case of mistakes or problems.
- Cross-platform: Everything has an app, but not everything should be. People barely get around to installing a calendar/scheduling app for people they live or work with, let alone this! A simple, clearview website.
- Accessible: Care should be put into the accessibility of the project. Mandatory image descriptions is a measure that - even though it might have to get a toggle down the line - an attempt at a step to making user-generated content more accessible, or at least thought about. Further care should also be put in providing as well-polished accessibility from the get-go.
Obviously, I developed this application with security in mind; following recommended practices wherever I could find. But I'm a programmer and not a cybersecurity expert! Please review the used practices and check with your own security standards. And if you have a suggestion/improvement, please feel free to open an issue/PR!
In app.ts, the secret is randomly generated on startup. This is to minimize configuration by not requiring a custom string to be set, whilst ensuring the string is secure, whilst not having any noticeable impact on the user experience (as the logins are meant to be temporary).
Currently the tests should be ran with the TZ
environment variable set to the same timezone your machine is Europe/Brussels. This is because JavaScript's new Date().getTimezoneOffset()
(which is used to determine correct resulting hours) does not allow custom timezone insertion.
For native HTML
date(time) input, you have...
date
(which doesn't include time)datetime-local
(which doesn't include timezone information)
No timezone-based datetime
is available.
To ensure compatibility with more devices and lower client-side footprint, the native datetime-local
input is used
(as opposed to a JS library solution).
- This returns no timezone information. The returned value is in the format of
YYYY-MM-DDTHH:MM
- This means that the input values will be from the users timezone point of view
JavaScript Date()
also includes time- Stored in UTC, specifically ms since January 1, 1970 00:00:00 UTC (see w3schools)
- I haven't have it gotten to consistently parse UTC strings with timezone information. This might be a goof on my end, though.
new Date().getTimezoneOffset()
is based on TZ environment variable.- JavaScripts UTC constructor can deal with too many hours being provided.
new Date(Date.UTC(2024, 1, 1, 25, 0)).toISOString()
returns"2024-02-02T01:00:00.000Z"
- Wrapper for JS Date(), but with better parsing and formatting.
- Should output according to the
WEBSITE_LOCALE
&WEBSITE_TIMEZONE
environment variables
process.env.tz
Returns aArea/City
format. See the Node.js docs for more information
- Has
{start,end}Date
&{start,end}Time
, both seemingly assuming the values to be local - timeZone config
- ATCB uses a library of the same developer for valid inputs for timeZone. See a few of the available notations in the source code here
- My best results were with using
Area/City
. This will be set in theWEBSITE_TIMEZONE
environment variable
TODO
Key | Explanation | default | default (Docker) |
---|---|---|---|
HOST_DOMAIN | Which domain the website/server will be reachable on | localhost:3000 |
not set |
DATA_DIR | Where to store data uploaded by users | data/ |
/app/data/ |
WEBSITE_TITLE | The title for your website, displayed in HTML, OpenGraph, views/index h1 | Community Pinboard! |
not set |
WEBSITE_DESCRIPTION | The description for your website, displayed in OpenGraph | A public event pinboard for your local community! |
not set |
* WEBSITE_LOCALE | The locale for your website. This will determine in what format datetimes are displayed in the rendered HTML/within app/Pin.ts | nl-be |
not set |
* TZ | The timezone in Area/City notation (see TZ identifier on Wikipedia list of database tz time zones). This will determine in what timezone datetimes are added to calendar. Additionally, view the process.env.TZ Node.js docs |
Europe/Brussels |
not set |
NODE_ENV | Node.js env variable to set environment | yarn prod: production / yarn test: test ** |
production |
ADMIN_PASSWORDS | Valid passwords for users to log in with. Passwords are separated using a pipe character '| ' |
not set | not set |
MAX_TITLE |
Max character length for pin title | 80 | not set |
MAX_DESCRIPTION |
Max character length for pin description | 400 | not set |
MAX_LOCATION |
Max character length for pin location | 150 | not set |
MAX_POSTEDBY |
Max character length for pin posted by | 50 | not set |
(*: recommended) (**: set by Jest)
For an example setup, see .env.example
- tests/: Tests for
app/
. See Install, run and test using Node.js - app/: Custom back-end code. Routing, saving pins to disk, the Pin class etc.
- .github/workflows/: Worksflows that run on the CI/CD system of GitHub, GitHub Actions. In this project it is used to deploy Docker images
- app/: Custom back-end code. Routing, saving pins to disk, the Pin class etc.
- bin/: auto-generated by
express-generator
, used as entrypoint. Leave unmodified unless specifically required - data/: auto-generated in runtime. Stores pin.json files, uploads...
- public/: front-end assets that do not get processed. Client-side CSS/JS, fonts, images...
- styles/: scss files that will be transpiled to public/stylesheets/style.css (auto-generated in runtime)
- views/: front-end html templates, written in Pug
- .dockerignore: Which files are ignored by Dockerfile
- .gitignore: Which files are ignored by git/version control
- app.ts: auto-generated by
express-generator
. Ignore unless specifically required - docker-compose.yml: file used to build and run using Docker Compose
- Dockerfile: file used to build a Docker image
- LICENSE: license details.
- package.json: package info. Stores startup scripts (
yarn start
), dependencies... - README.md: this file!
- tsconfig.json: TypeScript config file
- yarn.lock: auto-generated by yarn, updates when npm packages are added/removed
The non-edited post-it SVG is from Openclipart, licensed under the Public Domain. More information on the SVG can be found here.
The current (placeholder) background is from the Nookipedia assets page.
The cork.jpg material is...
- Created using
Cork001
from ambientCG.com, licensed under the Creative Commons CC0 1.0 Universal License. - Modified by @hynet-mel.
This project is licensed under the MIT License.