Skip to content

yqni13/artcreation-dv

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

438 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

yqni13 | $\texttt{\color{goldenrod}{ARTCREATION-DV}}$

$\textsf{\color{brown}{v1.5.6}}$



Angular       NodeJS       PostgreSQL       Neon       Cloudflare       RxJS       ExpressJS       i18n       BetterStack      

$\textsf{\color{teal}Hosting}$

This project runs live (see link below). The frontend is hosted by Netlify, while the backend is hosted by Vercel.
Data and images are managed via PostgreSQL database on Neon and cloudstorage by Cloudflare. For testing purposes, one instance runs on env:stag, while the live version runs on env:prod.

visit the WEBSITE


🪄 $\textsf{\color{salmon}Getting started}$

$\textsf{\color{teal}Prerequisites}$

  • node: v20+
  • Cloudstorage (R2 Object Storage)
  • Betterstack Telemetry (logging)

$\textsf{\color{teal}Local setup}$

Download or clone project

git clone https://github.com/yqni13/artcreation-dv

Create new .env file and fill in your credentials/other env data (see docs).
Navigate/cd into the root paths (/frontend and /backend) and install dependencies via npm:

$ npm ci

Additionally, the script to overwrite env data needs to be configured within set-env.ts (env:prod). Create a local copy (see docs) for local development. Start application (frontend) in local environment:

$ npm run start

which will open automatically on http://localhost:4200/. To run backend, use:

$ node server.js

🧩 $\textsf{\color{salmon}Features}$

Feature Description
🪁 Angular Angular v19 standalone with routing + nested routes on id
📂 Cloud file handling Upload/delete via Cloudflare R2 (S3-compatible) - supporting images up to 4MB
🖼️ Preload Customized image/video preload on page loading + viewport/scroll
⌨ Input Customized form components (text/textarea/select)
🎠 Carousel Customized carousel component
🎨 Themes Customized theme options (dark/light mode)
⚠️ Validation Customized validation in combination with Angular + Express-Validator
📧 Email Email service with node.js & nodemailer
🗯️ Notification Customized snackbar + extended translation service
📱 Design Responsive design 400px > width < 1800px supported via flexbox & media queries

$\textsf{\color{teal}Customized form}$

To contact the artist for product orders or general inquiries, a custom form is provided. Currently, this feature is not available in the live version due to the lack of backend hosting.

The form combines customized components, frontend/backend validation logic, nodemailer, and a Node.js service to send emails via a predefined no-reply account.

Validation checks ensure all required fields are filled, that the reference number follows the correct format, and that a valid selection has been made.
Figure 2 shows an example validation message: "ReferenceNr '561H65' does not exist".

 no picture found Figure 2

$\textsf{\color{teal}Internationalization}$

To reach an international audience of artists and art enthusiasts, the webpage was initially developed in English, with support for multiple languages implemented using the ngx-translate package (@ngx-translate/core + @ngx-translate/http-loader).

Currently, two languages are available: English and German (see Figure 3).

Static and dynamic texts are translated based on the selection made in the footer. The selected language is saved in localstorage, similar to the color theme, and persists between visits.

To simplify translation maintenance, the TranslateHttpLoader was customized to combine multiple .json files per language instead of the default single-file approach.

See custom translate loader for implementation details.

 no picture found Figure 3, v1.0.0-beta.4

$\textsf{\color{teal}Customized snackbar / interceptor}$

In case of unexpected responses or to visually confirm actions, a custom snackbar appears at the top right (or centered on screens smaller than 500px). The snackbar can be triggered with just two required inputs (title + type), and optionally extended with up to five configuration parameters.

To enhance contrast, each of the four message types uses a distinct color: $\textsf{\color{red}{error}}$, $\textsf{\color{royalblue}{info}}$, $\textsf{\color{green}{success}}$, $\textsf{\color{orange}{warning}}$.

Figure 4 shows an example error message indicating that the email could not be sent (highlighted in red), triggered by an HTTP interceptor when no backend is available.

 no picture found Figure 4

$\textsf{\color{teal}Customized lazy loading / preload}$

Instead of Angular’s built-in @defer blocks, this application uses a custom lazy loading strategy via HostListeners.

When opening the Gallery component, all images currently within the viewport are rendered immediately. Additionally, a buffer of images just below the viewport is preloaded to ensure a smooth scrolling experience. As the user scrolls, more images are continuously preloaded.

Figure 5 illustrates how 6 images inside the viewport, along with the next 3 rows of images, are shown as preloaded in the network tab of DevTools.

 no picture found Figure 5, v1.0.0-beta.3

$\textsf{\color{teal}Theme settings}$

The webpage offers two theme settings: $\textsf{\color{gray}{dark mode}}$ & $\textsf{\color{goldenrod}{light mode}}$. The active setting is stored in the localstorage with dark mode as the default.

             Figure 6

$\textsf{\color{teal}Reactive images}$

Most images have additional logic attached for either displaying more details or scaling them up. In the news archive, additional text content is shown; clicking the magnifier icon displays the image in full resolution.

In the gallery section, preview thumbnails open in a museum-style view, showing all available details about the artwork. Clicking the image again displays it at maximum resolution (see Figure 7).

 no picture found Figure 7

$\textsf{\color{teal}Database layer}$

PostgreSQL is used as the relational database management system to store all necessary data. The free-tier plan from the Neon hosting service is sufficient to handle all data in this context (see Figure 8, basic findAll request).
Migrations are handled with the node package node-pg-migrate in the backend (see docs)).

Image files for "gallery" and "news" elements are not stored in the database; only their paths are saved within the respective entries (see Figure 8, response). Additionally, files submitted by users (for "gallery" or "news" items) are processed (regarding format and size) and uploaded to a cloud object storage, in this case an R2 bucket from Cloudflare.

Once the data is retrieved from the database, the saved image path is concatenated with a cloud-specific access URL to form the full image URL (see Figure 9, red highlight). The images are then loaded from the cloud or cache.

 no picture found Figure 8, v1.0.0-beta.13

 no picture found Figure 9, v1.0.0-beta.13

$\textsf{\color{teal}Administration}$

Data related to the "gallery" and "news" elements can be managed by the administrator via login and a dedicated administration area. While "gallery" data is accessible through the "gallery" section in the navigation bar, "news" items are displayed on the "home" page and in the archive. On the "home" page, the three latest "news" entries are presented using a carousel component.

The archive lists all "news" entries in descending chronological order. Features such as text-based search and sorting will be available in a future version.

The application supports single-file uploads (maximum 4MB) from the user’s local device to associate an image with a newly created item. Alternatively, a "news" item can be linked to an existing "gallery" entry (see Figure 11: select an existing artwork). Using a foreign key referencing the linked "gallery" item's ID, a LEFT JOIN SQL query is used to retrieve the necessary and up-to-date data.

SELECT
  ${tableNews}.*,
  ${tableGallery}.image_path AS image_path_${tableGallery},
  ${tableGallery}.thumbnail_path AS thumbnail_path_${tableGallery},
  ${tableGallery}.reference_nr AS reference_nr_${tableGallery},
  ${tableGallery}.art_genre AS art_genre_${tableGallery}
FROM ${tableNews}
LEFT JOIN ${tableGallery} ON ${tableNews}.gallery = ${tableGallery}.gallery_id
ORDER BY ${orderPrio1} DESC

The provided image paths allow images to be loaded without additional database queries. The reference number and art genre offer sufficient information to navigate directly from a news article to the corresponding artwork details (see Figure 10).

 no picture found Figure 10, v1.1.0

📝 $\textsf{\color{salmon}Logging}$

Currently, for the UI, only console logs and snackbar notifications inform users about errors and warnings. For the backend, the logging framework Winston is used in combination with Logtail from BetterStack for easy access and long-term storage (see Figure 11, test phase).

 no picture found Figure 11, v1.0.2

🔧 $\textsf{\color{salmon}Testing}$

$\textsf{\color{teal}Jest}$

The jest testing framework was added to the project, providing unit-tests and integration-tests for the backend.
Install the packages @jest/globals, @types/jest and supertest in addition to jest:

npm install jest @jest/globals @types/jest supertest --save-dev

Only some basic tests exist currently for utils (see tests).
Run tests on local device by including setup for dotenv/config to provide environment variables:

set MODE=staging && jest --setupFiles dotenv/config

or simply save as script command in package.json to run npm test:

  "scripts": {
    "start": "node server.js",
    "test": "set MODE=staging && jest --setupFiles dotenv/config"
  }

To automatically run tests before merging a feature/development branch upstream, a GitHub Action is set up (see main.yml).
To prevent an unwanted merge due to an unfinished or failed test run, the project is set up to disable merging until all tests have passed (see Figure 12).

 no picture found Figure 12, v1.2.7

$\textsf{\color{teal}Cross-browser testing}$

Firefox Chrome Opera Edge DuckGo Brave
Yes* Yes Yes Yes Yes Yes

*This browser has problems with some functionality.


$\textsf{\color{teal}Angular ESLint}$

Angular ESLint was added to the project as the next step of testing.
Install ESLint global via node package manager:

$ npm install -g eslint

Install ESLint local for angular project:

$ ng add @angular-eslint/schematics

Run ESLint to list all current lint errors:

$ npm run lint

📈 $\textsf{\color{salmon}Updates}$

see changelog for all updates

$\textsf{\color{forestgreen}last update:}$

$\textsf{[v1.5.3\ =&gt;\ {\textbf{\color{brown}v1.5.6}]}}$ app

  • $\textsf{\color{black}Deletion:}$ Deleted files related to the docker configuration.
  • $\textsf{\color{orange}Patch:}$ Updated:
    • fn reset(...) (support component) does not change support option on manual reset.
    • extracted fn scrollToTop(...) to navigation service.

Aimed objectives for next $\textsf{\color{green}minor}$ update:

- pagination in archive component
- provide security standards: input sanitizations, content security policies & HttpOnly cookies
- deploy a Web Application Manifest to make webpage into a progressive web app (PWA)

Aimed objectives for next $\textsf{\color{cyan}major}$ update:

- direct pay option