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
Copy file name to clipboardExpand all lines: backend/README.md
+10-10Lines changed: 10 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -101,38 +101,38 @@ Stories was the first user-generated content feature and is pretty self-containe
101
101
102
102
Stories are moderated by admins. All stories are submitted to the moderation queue at http://1940s.nyc/admin/review-stories.
103
103
104
-
Automatic moderation was considered but most of the rejected stories are not classic spam that could be detected by spam filters or CAPTCHAs but rather trolls and confused people.
104
+
Automatic moderation was considered but most of the rejected stories are not spam that could be detected by spam filters or CAPTCHAs but trolls or users who misuse the feature.
105
105
106
106
### Users and authentication
107
107
108
-
I didn't want to pay for an authentication service, and it seemed simple enough to build my own.
109
-
I wanted a more seamless user experience without usernames and passwords, and often even without doing anything.
108
+
For a seamless user experience and to reduce costs, a custom authentication system was built instead of using a third party service like Auth0.
110
109
111
-
For any route tagged with `@Security('user-token')`, a user is created if one does not exist. The user is then considered logged in immediately without any information and is considered anonymous. Later, the user can provide, and optionally verify an email address. Specific features can check for verified email addresses if that level of security is needed. Corrections to geocodes, for example, require a verified email address. Colorization, however, can be done by anonymous users, allowing a "free trial" experience.
110
+
For any route tagged with `@Security('user-token')`, a user is created if one does not exist. The user is then considered logged in immediately without any information and is considered anonymous. Later, the user can provide, and optionally verify an email address. Specific features can check for verified email addresses if that level of security is needed. Corrections to geocodes, for example, require a verified email address. Colorization, however, can be done by anonymous users, allowing a limited "free trial" experience.
112
111
113
112
**Log-in process**: The user supplies an email address: if an account exists the user is sent a magic link to log in, or the email is associated with the current possibly anonymous account they are logged in with. Magic links are JWT tokens.
114
113
115
-
Notably, **Stories** are not connected to Users because Stories were built first. Users primarily support the Colorization feature for payment and credit ledgering and the Corrections feature for safety.
114
+
Notably, **Stories** are not connected to Users because Stories were built first with their own authentication mechanism. Users primarily support the Colorization feature for payment and credit ledgering and the Corrections feature for safety.
116
115
117
116
### Credit ledgering
118
117
119
-
Users can purchase "Color tokens" to colorize images. This is managed via the Ledger system, which is just a ledger of credits issued and images colorized. Users can go negative as we allow one free colorization per day.
118
+
Users can purchase "Color tokens" to colorize images. This is managed via the Ledger system, which is just a ledger of credits issued and images colorized. Users can go negative as we allow one free colorization per day as a trial.
120
119
121
-
`LedgerService.withMeteredUsage` is a wrapper to wrap code that uses requires and consumes credits.
120
+
`LedgerService.withMeteredUsage` is a wrapper to wrap code that requires and consumes credits.
122
121
123
122
### Admin users
124
123
125
-
Admin users actually _do_ use an authentication service: Netlify Identity. This was built before end-user authentication and could potentially be updated to use the same system.
124
+
Admin users actually _do_ use a third-party authentication service: Netlify Identity. This was built before end-user authentication and could potentially be updated to use the same system.
126
125
127
126
Admin users have roles defined in Identity.
128
127
129
128
A route tag for an admin route looks like `@Security('netlify', ['moderator'])`. This requires an Identity user to be logged in and have the role `moderator`.
130
129
131
130
### Email campaigns
132
131
133
-
I was also too cheap to pay for a mailing list service like Mailchimp so I built one.
132
+
1940s.nyc has an occasional newsletter. To avoid the costs of a third-party service like Mailchimp, a simple system was built into the app.
134
133
135
-
It's pretty simple. When a campaign is enqueued via the API it just creates a record for every list member. A cron job sends out the emails in batches.
134
+
It's pretty simple. When a campaign is enqueued via the API it just creates a sending record for every list member. A cron job sends out the unsent emails in batches.
135
+
The email content lives in Postmark templates.
136
136
137
137
There's currently no sign-up form for the mailing list. Addresses are just added whenever they provide an email via other app features like Stories.
Copy file name to clipboardExpand all lines: frontend/README.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -78,7 +78,7 @@ Zustand is an unopinionated framework, but this project has opinions.
78
78
- Zustand does not natively support computeds, so we have a separate hook co-located with the store
79
79
- Stores should clearly define their Actions and State, separately, using typescript interfaces
80
80
81
-
A store must be created in a file called \*Store.ts and exported as the default export. Ad-hoc stores shouldn't be created in components.
81
+
A store must be created in a file called \*Store.ts in a `stores` directory and exported as the default export. Ad-hoc stores shouldn't be created in components.
82
82
83
83
```typescript
84
84
importcreatefrom'zustand';
@@ -187,4 +187,4 @@ This project uses Typescript.
187
187
188
188
API calls are written manually in utils files and use `axios`, with named exports matching API functions.
189
189
190
-
There is no automatic generation of API clients, though it is possible to do, since the backend does produce an OpenAPI spec.
190
+
There is no automatic generation of API clients, but this could be done in a future project based on the spec generated by the backend.
0 commit comments