You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
+
9
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+
11
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
+
13
+
---
14
+
15
+
All learning content (within the /docs folder) is licensed under:
16
+
17
+
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License — <https://creativecommons.org/licenses/by-nc-sa/4.0/>
Copy file name to clipboardExpand all lines: README.md
+19-11
Original file line number
Diff line number
Diff line change
@@ -1,18 +1,10 @@
1
-
> [!CAUTION]
2
-
>
3
-
> **Note for future Jits:** you put this particular part of the tech stack on ice in Feb 2025 ([ref](https://www.notion.so/jits/v2-On-Ice-Maintenance-1ab2a607a9ea807b92c3ff391ca91ac4?pvs=4)). You _did_ complete the migration to Angular v19 etc. ([ref](https://www.notion.so/jits/Angular-v19-etc-upgrades-1272a607a9ea80d48ca1e57c291a4836?pvs=4)) but didn't update the docs (because, why bother?). Just bear this mind if you ever resurrect this repo.
4
-
5
1
# The [FullStacksDev](https://fullstacks.dev) Angular and Firebase simple example app
6
2
7
3
Part of the curated [**FullStacksDev Angular and Firebase tech stack**](https://fullstacks.dev/#angular-and-firebase). For solo devs and very small teams.
8
4
9
5
This is a fairly simple **Logbook app** — to keep a single time-ordered log of text entries — focused on showcasing and learning the tech stack, built from the [base template](https://github.com/FullStacksDev/angular-and-firebase-template).
10
6
11
-
You can read more about the [purpose and specs of the example apps](https://fullstacks.dev/example-apps-and-patterns) on our website.
12
-
13
-
> [!IMPORTANT]
14
-
>
15
-
> This is currently in **beta**. We're actively working on it and will be making regular updates — expect big changes and improvements until it gets to a stable release. Feel free to give your feedback and suggestions via the Issues tab.
7
+
You can read more about the [purpose and specs of the example apps](TODO) on our website.
16
8
17
9
## Running the app locally
18
10
@@ -77,6 +69,22 @@ To make the information skimmable and easier to understand, you'll see the follo
77
69
>
78
70
> More severe gotchas and things to watch out for.
79
71
80
-
## A note about the patterns example app
72
+
## Licenses
73
+
74
+
> [!IMPORTANT]
75
+
>
76
+
> This example app and all code and content is provided "as is" and with no warranty nor liability. Please make sure you keep a close eye on any costs incurred as you'll be liable for these and anything else that arises from using this template. We recommend you review the code and architecture carefully, adapt it to your needs and thoroughly test your solutions out, before deploying to a live project, paying close attention to [Firebase's pricing model](https://firebase.google.com/pricing).
77
+
78
+
### Code
79
+
80
+
All code here is licensed under the MIT License — see the [LICENSE](./LICENSE) file for details.
81
+
82
+
### Content
83
+
84
+
<p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/">All learning content within the `/docs` folder is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1" alt=""></a></p>
85
+
86
+
> [!IMPORTANT]
87
+
>
88
+
> This means you cannot use the learning content for commercial purposes (but you can use the code for commercial apps), and if you reproduce the learning content anywhere you must attribute it to FullStacksDev and you must share any derivative works under the same license.
81
89
82
-
Throughout the docs we reference the patterns example app (coming soon). This is a dedicated place for showcasing even more in-depth capabilities and patterns to bring out the best in this tech stack. It's a perfect next step to take after you've understood and learnt from this simple example app.
Copy file name to clipboardExpand all lines: docs/1.architecture.md
+6-18
Original file line number
Diff line number
Diff line change
@@ -15,18 +15,10 @@ This simple example app is frontend-heavy in that the majority of the functional
15
15
- Updated routes in the [`app/src/app/app.routes.ts`](../app/src/app/app.routes.ts) file to lazily load the logbook feature routes.
16
16
- A link to "Open logbook" in the navigation of the website's static pages (i.e. in [`app/src/app/website/website-shell.component.ts`](../app/src/app/website/website-shell.component.ts)).
17
17
18
-
|**:white_check_mark: Pattern**|
19
-
| :-- |
20
-
| We don't use [Angular modules (i.e. `@Module`)](https://angular.dev/guide/ngmodules) for our own code — we've chosen to go all-in on [Angular's recent **standalone** approach](https://angular.dev/guide/components/importing#standalone-components). So we only ever define (and prefer to import) standalone components, directives, etc.<br><br> The base template has configured the Angular CLI generator to always set the `standalone: true` flag on any components, directives, etc. you generate. |
21
-
22
18
|**:brain: Design decision**|
23
19
| :-- |
24
20
| Since this app is frontend-heavy we've decided to put all the data model types (and other useful types) in a file within the `app` folder, as opposed to putting these in [`firebase/common/models.ts`](../firebase/common/models.ts) (as provided by the base template) where they would be available to both the frontend and backend. |
25
21
26
-
> [!NOTE]
27
-
>
28
-
> In the patterns example app (coming soon) we show you how to better share data model types between the frontend and backend.
29
-
30
22
### The logbook feature
31
23
32
24
```text
@@ -61,7 +53,7 @@ We'll dig into these in more detail in later documents.
61
53
62
54
|**:white_check_mark: Pattern**|
63
55
| :-- |
64
-
| As mentioned in the base template, we highly recommend separating the code within the top-level feature folders into the following subfolders: **`data`**, **`feature`**, **`ui`** and **`util`**. And trying to keep both the top-level feature folders and these subfolders at one hierarchical level. We've found that this is a great starting folder structure (and general architecture) which helps you quickly find stuff, whilst spending minimal time on figuring out what goes where.<br><br>The `data` folder is for (most) state management and data access services. Page and smart components go in the `feature` folder, whilst presentational components go in the `ui`folder. And the `util` folder is for standalone utilities.<br><br>This is a recommended folder structure based on [Nx's suggested library types](https://nx.dev/concepts/more-concepts/library-types).<br><br>For features within the `shared` folder you should follow the same structure, except you probably won't need a `feature` subfolder within each shared feature since these are shared bits of code for use elsewhere.<br><br>As things grow you may need to adapt and tweak this structure (e.g. to add another level in the hierarchy) — we'll see how to tackle this in the patterns example app (coming soon). |
56
+
| As mentioned in the base template, we highly recommend separating the code within the top-level feature folders into the following subfolders: **`data`**, **`feature`**, **`ui`** and **`util`**. And trying to keep both the top-level feature folders and these subfolders at one hierarchical level. We've found that this is a great starting folder structure (and general architecture) which helps you quickly find stuff, whilst spending minimal time on figuring out what goes where.<br><br>The `data` folder is for (most) state management and data access services. Page and smart components go in the `feature` folder, whilst presentational components go in the `ui`folder. And the `util` folder is for standalone utilities.<br><br>This is a recommended folder structure based on [Nx's suggested library types](https://nx.dev/concepts/decisions/project-dependency-rules).<br><br>For features within the `shared` folder you should follow the same structure, except you probably won't need a `feature` subfolder within each shared feature since these are shared bits of code for use elsewhere.<br><br>As things grow you may need to adapt and tweak this structure (e.g. to add another level in the hierarchy). |
65
57
66
58
> [!IMPORTANT]
67
59
>
@@ -71,11 +63,11 @@ We'll dig into these in more detail in later documents.
71
63
>
72
64
> With the caveat that forms _sometimes_ don't behave well with OnPush change detection, so in rare cases you'd need to use the `ChangeDetectorRef` to manually mark a component for change detection.
73
65
>
74
-
> As long as you stick to the approaches promoted in the example apps you should not encounter any change detection issues (i.e. where underlying data changes but the UI does not update).
66
+
> As long as you stick to the approaches promoted in this example app you should not encounter any change detection issues (i.e. where underlying data changes but the UI does not update).
75
67
76
68
### Data flows, app logic and UI components architecture
77
69
78
-
Within the frontend app, it's important to have an architecture in place for reasoning about data flows, app logic and UI components with some "rules" to make things predictable and easy to scale up with more features, and manage growing complexity. Thus, knowing where things go and how data flows between backend, services, and components is crucial.
70
+
Within the frontend app, it's important to have an architecture in place for reasoning about data flows, app logic and UI components with some rules to make things predictable and easy to scale up with more features, and manage growing complexity. Thus, knowing where things go and how data flows between backend, services, and components is crucial.
79
71
80
72
We highly recommend the following generalized data and logic flows — we follow this extensively in the example apps:
81
73
@@ -98,7 +90,7 @@ sequenceDiagram
98
90
- Use Angular services to wrap ALL access to databases and external services.
99
91
- Use state management "stores" to encapsulate as much of the app's state and behavior as possible, leaving components to focus on UI needs, triggering store behaviors and responding to state changes.
100
92
- Use smart components to interact with stores to bind state and trigger application logic.
101
-
- Use presentational components (within the template of smart components) to abstract out UI presentation and logic in a way that does not need to know about the overall application state and structure, communicating all actions/events back to the parent smart component.
93
+
- Use presentational components — within the template of smart components — to abstract out UI presentation and logic in a way that does not need to know about the overall application state and structure, communicating all actions/events back to the parent smart component.
102
94
103
95
We'll cover these in more detail, in the context of the simple logbook feature, in later documents.
104
96
@@ -116,7 +108,7 @@ We'll cover these in more detail, in the context of the simple logbook feature,
116
108
>
117
109
> … think:
118
110
>
119
-
> _"How do these actions and events change the state of the application? How can I use this state to drive UI and flows, or what additional state do I need to model?"_
111
+
> _"How do these actions and events change the state of the application? How can I use this state to drive UI and flows, and what additional state do I need to model?"_
120
112
121
113
There are different levels of stores, scoped to particular contexts:
122
114
@@ -151,14 +143,10 @@ We don't make use of Firebase Functions in this simple example app, partly so it
151
143
152
144
> [!IMPORTANT]
153
145
>
154
-
> If you're used to a more traditional client-server access model where the server controls all access to a database via an API then Firebase's approach of making direct database calls from the client-side may seem counter-intuitive (and even scary) at first. If it helps, consider that there is still _some form of an API_ that these database calls go through — the security rules, which essentially encode the business logic on what can and cannot be accessed, in its own domain specific language (albeit limited to access and basic validation).
146
+
> If you're used to a more traditional client-server access model where the server controls all access to a database via an API then Firebase's approach of making direct database calls from the client-side may seem counter-intuitive (and even scary) at first. If it helps, consider that there is still _some form of an API_ that these database calls go through — i.e. the security rules, which essentially encode the business logic on what can and cannot be accessed, in its own domain specific language (albeit limited to access and basic validation).
155
147
>
156
148
> You can still achieve a more traditional server-side API style with Firebase Functions and the Firebase Admin SDK, but we don't use that in this simple example app.
157
149
158
-
> [!NOTE]
159
-
>
160
-
> We use Firebase functions extensively in the patterns example app (coming soon), for capabilities that need proper backend support and can't be achieved with just client side code and Firebase's security rules.
161
-
162
150
> [!WARNING]
163
151
>
164
152
> It's best to have as much encoded in the codebase as possible, especially the security rules and indexes, in their relevant files, which will be pushed to Firebase as part of the deployment run.
Copy file name to clipboardExpand all lines: docs/2.routes-and-shell.md
+2-6
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@
6
6
7
7
The base template comes with a `website` feature folder (within the `app`) where the static pages live. We could've added more pages and components here to build our logbook app, but it's better to separate it out into a dedicated feature folder ([`app/src/app/logbook/`](../app/src/app/logbook/)) and lazily load it only when the user navigates to a particular URL — `/logbook` in this case — as registered in the top-level app routes file:
Here, the use of an `import` for the `loadChildren` property tells Angular to separate out the code for the logbook feature into its own bundle and only load it when the user navigates to `/logbook`.
12
12
@@ -16,7 +16,7 @@ Here, the use of an `import` for the `loadChildren` property tells Angular to se
16
16
17
17
Let's now look at the routes for the logbook feature itself:
- We define a parent route that will load the `LogbookShellComponent`, with child routes defined within.
22
22
- This shell component has a `<router-outlet>` in its template where a matching child route will have it's component placed in to.
@@ -51,10 +51,6 @@ At the moment, the [`app/src/app/logbook/logbook-shell.component.ts`](../app/src
51
51
52
52
In the next few documents we dig into how the feature is built.
53
53
54
-
> [!NOTE]
55
-
>
56
-
> In the patterns example app (coming soon) we showcase a bigger feature with multiple pages and a shell component that provides a common UI and navigation elements. All of this uses a more complex route structure with multiple child routes and route parameters.
0 commit comments