Learn by doing
Work through focused learning units, exercises, hackathons and an end-to-end capstone project.
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1014ba7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..95f03ba --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: monthly + groups: + astro: + patterns: ["astro", "@astrojs/*"] + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6dbdc85 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +name: CI + +on: + push: + branches: [dev] + pull_request: + branches: [dev, main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + quality: + name: Build and verify + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out repository + uses: actions/checkout@v7 + - name: Set up Node.js + uses: actions/setup-node@v7 + with: + node-version: 24 + cache: npm + - name: Install dependencies + run: npm ci + - name: Verify production promotion source + if: github.base_ref == 'main' && github.head_ref != 'dev' + run: | + echo "::error::Only the dev branch may be promoted to main." + exit 1 + - name: Check formatting + run: npm run format:check + - name: Type-check and test production build + run: npm run check + - name: Audit performance, accessibility and SEO + uses: treosh/lighthouse-ci-action@v12 + with: + configPath: ./lighthouserc.json + uploadArtifacts: true diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..5830bfd --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,57 @@ +name: Deploy to Cloudflare Pages + +on: + push: + branches: [dev, main] + workflow_dispatch: + +permissions: + contents: read + deployments: write + +concurrency: + group: cloudflare-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + deploy: + name: Verify and deploy + runs-on: ubuntu-latest + timeout-minutes: 15 + environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }} + steps: + - name: Check out repository + uses: actions/checkout@v7 + - name: Set up Node.js + uses: actions/setup-node@v7 + with: + node-version: 24 + cache: npm + - name: Install dependencies + run: npm ci + - name: Verify production build + env: + CLOUDFLARE_WEB_ANALYTICS_TOKEN: ${{ vars.CLOUDFLARE_WEB_ANALYTICS_TOKEN }} + run: npm run check + - name: Record deployment identity + run: node scripts/write-deployment-metadata.mjs dist "$GITHUB_SHA" "$GITHUB_REF_NAME" + - name: Deploy branch to Cloudflare Pages + id: deploy + uses: cloudflare/wrangler-action@v4 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + wranglerVersion: "4" + command: pages deploy dist --project-name=${{ vars.CLOUDFLARE_PAGES_PROJECT || 'ldsa-website' }} --branch=${{ github.ref_name }} --commit-hash=${{ github.sha }} + gitHubToken: ${{ secrets.GITHUB_TOKEN }} + - name: Verify deployed site + env: + DEPLOYMENT_URL: ${{ steps.deploy.outputs.deployment-url }} + DEPLOYMENT_ALIAS_URL: ${{ steps.deploy.outputs.pages-deployment-alias-url }} + EXPECTED_COMMIT: ${{ github.sha }} + EXPECTED_BRANCH: ${{ github.ref_name }} + EXPECT_NOINDEX: ${{ github.ref != 'refs/heads/main' }} + EXPECT_ANALYTICS: ${{ vars.CLOUDFLARE_WEB_ANALYTICS_TOKEN != '' }} + CF_ACCESS_CLIENT_ID: ${{ secrets.CF_ACCESS_CLIENT_ID }} + CF_ACCESS_CLIENT_SECRET: ${{ secrets.CF_ACCESS_CLIENT_SECRET }} + run: npm run check:deployment diff --git a/.gitignore b/.gitignore index 1301e01..2cbd17e 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,9 @@ vite.config.ts.timestamp-* # Turbo Repo .turbo + +# Cloudflare local state and platform files +.wrangler/ + +# OS metadata +.DS_Store diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..a45fd52 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +24 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..739188c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +dist +node_modules +migration/raw +package-lock.json +public/images diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2686032 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,14 @@ +# Contributing + +Thank you for helping maintain the LDSA website. + +1. Branch from `dev` using a name such as `feature/update-prep-course`. +2. Keep time-sensitive operational details in the LDSA wiki and link to them from the site. +3. Run `npm ci`, `npm run check` and `npm run format:check`. +4. Open a pull request into `dev` and explain the visible change and how it was checked. +5. Test the merged result on the protected Cloudflare `dev` deployment. +6. Promote tested changes with a pull request from `dev` to `main`. + +Do not put subscriber exports, application data, API tokens or other secrets in the repository. + +When changing a Flodesk form, preserve the form ID, field names and preference values unless the matching Flodesk configuration has also changed. Complete the account-level submission checks in `docs/operations/qa.md` before production promotion. diff --git a/README.md b/README.md index 0ca8cc1..45cee09 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,89 @@ -# website -LDSA website +# LDSA Website + +The official website of the [Lisbon Data Science Academy](https://www.lisbondatascience.org/). It is a static [Astro](https://astro.build/) site designed for Cloudflare Pages and maintained through the `feature/* → dev → main` workflow. + +The hosting and delivery architecture uses free tooling and service tiers. Domain registration and renewal are the only expected website infrastructure cost. + +- Production: `https://www.lisbondatascience.org/` (kept on Unbounce until the migration acceptance tests pass) +- Candidate production: `https://ldsa-website.pages.dev/` +- Integration preview: `https://dev.ldsa-website.pages.dev/` + +## Local development + +Use Node.js 24 or newer: + +```bash +npm ci +npm run dev +``` + +The local server prints its URL, normally `http://localhost:4321/`. + +Before opening a pull request, run: + +```bash +npm run check +npm run format:check +``` + +`npm run check` type-checks the Astro source, builds the production site, validates internal links and local assets, rejects Unbounce dependencies, verifies the three preserved Flodesk endpoints, and confirms Cloudflare deployment files and the sitemap are present. After each Cloudflare deployment, GitHub Actions also checks the live routes, redirects, 404 page, security and indexing headers, sitemap, and deployed commit identity. + +## Branches and deployment + +- `feature/*`: one focused change; open a pull request into `dev`. +- `dev`: integration branch and protected Cloudflare preview. +- `main`: production branch. Merging here publishes the production build. + +Pull requests into `dev` or `main` run formatting, type checks, a clean production build, site contract checks and Lighthouse audits. Feature branches never deploy to Cloudflare. A push to `dev` deploys the private development preview, while a push to `main` deploys production through the Cloudflare Wrangler GitHub Action. + +The deployment workflow requires: + +- GitHub secret `CLOUDFLARE_API_TOKEN`, scoped to edit Cloudflare Pages. +- GitHub secret `CLOUDFLARE_ACCOUNT_ID`. +- Optional GitHub variable `CLOUDFLARE_PAGES_PROJECT`; it defaults to `ldsa-website`. +- Production-environment variable `CLOUDFLARE_WEB_ANALYTICS_TOKEN` after the final public hostname is registered in Cloudflare Web Analytics. Preview builds deliberately omit it. + +See [the Cloudflare runbook](docs/operations/cloudflare.md) for project creation, preview access, analytics and domain cutover. + +## Repository structure + +```text +src/ +├── components/ shared navigation, footer, FAQ and Flodesk forms +├── data/ navigation, links and migrated content data +├── layouts/ metadata and global page shell +├── pages/ public routes +└── styles/ design system and responsive styles +public/ assets and Cloudflare Pages configuration +scripts/ build-time contract checks +migration/ +├── raw/ public rendered-source snapshot from Unbounce +├── scripts/ migration audit helpers +└── *.md public-evidence audit, inventories and decisions +docs/operations/ deployment, DNS, QA and maintenance runbooks +.github/workflows/ CI and deployment automation +``` + +## Updating content + +Most page copy lives in `src/pages`. Shared links, FAQs and the preserved volunteer roster live in `src/data/site.ts`. Keep time-sensitive dates in the LDSA wiki where possible and link to that source of truth instead of duplicating values that will become stale. + +Images in `public/images` are locally hosted copies of LDSA assets recovered from the public Unbounce site. Add descriptive `alt` text for meaningful images and use an empty `alt` only for decorative images. + +## Flodesk forms + +`src/components/FlodeskForm.astro` preserves the three production Flodesk form IDs and submission endpoints: + +- General interest: `63f9e4e2f0116a4cabfef7db` +- Starters Academy: `615c9641c71e8685f183bd18` +- Prep Course: `6172e62fe625581864e3f857` + +The homepage also preserves the `option1` and `option2` interest values used by the current form. Do not replace these IDs or option values without updating the form in Flodesk and completing the end-to-end tests in [the QA runbook](docs/operations/qa.md). + +## DNS and production safety + +The selected cutover keeps authoritative DNS at Namecheap: `www` will become a CNAME to Pages and the apex will use Namecheap's permanent URL redirect to `www`. Email-related MX and TXT records remain untouched. The captured baseline, exact cutover and rollback sequence are in [the DNS runbook](docs/operations/dns.md). + +## Contributing + +Create a branch from `dev`, make a focused change, run the local checks, then open a pull request into `dev`. After the combined changes pass on the protected Cloudflare preview, open a pull request from `dev` into `main`. diff --git a/astro.config.mjs b/astro.config.mjs new file mode 100644 index 0000000..51e9373 --- /dev/null +++ b/astro.config.mjs @@ -0,0 +1,12 @@ +import { defineConfig } from "astro/config"; +import sitemap from "@astrojs/sitemap"; + +export default defineConfig({ + site: "https://www.lisbondatascience.org", + output: "static", + trailingSlash: "always", + integrations: [sitemap()], + build: { + format: "directory", + }, +}); diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..f18e87c --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,49 @@ +# Website architecture + +## System shape + +```text +GitHub repository + ├─ feature/* pull requests ── CI ──> dev + ├─ dev ── verified GitHub Action ──> protected Cloudflare preview + └─ main ── verified GitHub Action ──> Cloudflare production + │ + ├─ static HTML, CSS and images + ├─ Flodesk form submissions + ├─ LDSA Portal and Wiki links + └─ privacy-enhanced YouTube embed +``` + +The site is generated at build time by Astro and deployed as static files. There is no application server, database, runtime JavaScript framework or server-side session. Cloudflare provides TLS, CDN caching, preview deployments, Access control, deployment history and production Web Analytics. + +All migration infrastructure uses free services and open-source tooling: Astro, Node.js, npm, GitHub Actions within the repository's included allowance, Cloudflare Pages, Cloudflare Web Analytics, and Cloudflare Access Free for the small LDSA testing group. The domain registration/renewal remains the only unavoidable website infrastructure cost. Do not add a paid hosting, build, monitoring, analytics, testing, or CDN dependency without an explicit architecture decision. + +## Why Astro + +Astro provides reusable components and typed content without shipping a client framework to visitors. Header, footer, metadata, FAQs and Flodesk markup have one maintained implementation. Pages remain ordinary semantic HTML in the build output, which keeps performance high and reduces the maintenance surface for volunteers. + +## Why there is no Docker image + +The deployable artifact is the deterministic `dist` directory. GitHub-hosted runners and Cloudflare Pages only need the locked Node.js toolchain to create it. A Docker image would add another dependency and patching surface without improving runtime parity because there is no container at runtime. The `.nvmrc`, `engines` field and `package-lock.json` already pin the relevant build environment. + +## Content ownership + +- Stable marketing and explanatory content lives in version-controlled Astro pages. +- Shared navigation, official links, FAQs and roster data live in `src/data/site.ts`. +- Batch dates, admissions rules and other frequently changing details live in the LDSA wiki and are linked from the website. +- Subscriber records and email automations remain in Flodesk. +- Applications remain in the LDSA Portal. + +This separation prevents the website from becoming a second, stale source of truth for operational course details. + +## Integration boundaries + +Flodesk form identifiers, endpoints, preference values, configuration and runtime bundles are treated as public integration contracts and covered by the production-build test. A successful browser submission still requires Flodesk account verification because only Flodesk can prove which subscriber group and automation received the address. + +External destinations use normal links. The YouTube video uses the privacy-enhanced domain and lazy loading. Cloudflare's project-wide automatic analytics injection is disabled because it would mix private preview traffic into production data. The layout emits the free Web Analytics beacon only when the production GitHub environment supplies `CLOUDFLARE_WEB_ANALYTICS_TOKEN`; the build adds the matching CSP origins at the same time. Preview and ordinary local builds contain neither the beacon nor its CSP permissions. + +## Security and privacy + +Cloudflare `_headers` set a restrictive Content Security Policy, disable framing, narrow browser capabilities and prevent MIME sniffing. The policy allows only the Flodesk and YouTube origins needed by current features. Deployment credentials live in GitHub Secrets and are limited to Pages edit access. Preview access will be enforced by Cloudflare Access after the dashboard policy and CI service token in the Cloudflare runbook are configured. + +The repository must never contain Unbounce lead exports, subscriber lists, Cloudflare tokens or other personal/secret data. diff --git a/docs/operations/cloudflare.md b/docs/operations/cloudflare.md new file mode 100644 index 0000000..3f9c193 --- /dev/null +++ b/docs/operations/cloudflare.md @@ -0,0 +1,89 @@ +# Cloudflare Pages runbook + +The repository uses GitHub Actions and Wrangler Direct Upload. This keeps the build and deployment checks in one auditable workflow instead of asking Cloudflare and GitHub to build the same commit independently. + +The project must remain on free infrastructure. Cloudflare Pages serves this static site without Pages Functions, paid Workers, R2, or another billable runtime. Preview authentication uses the Cloudflare Zero Trust Free plan, which currently supports up to 50 users. Confirm that the dashboard still shows the Free plan whenever enabling a new Cloudflare product. + +## 1. Create the Pages project + +In the LDSA Cloudflare account, create a Pages project named `ldsa-website` using Direct Upload. Do not attach the production domain yet. + +If Wrangler is authenticated locally, the equivalent command is: + +```bash +npx wrangler pages project create ldsa-website --production-branch main +``` + +The build output is `dist`. The GitHub deployment workflow sends only `dev` and `main` with their real branch names. The two operational environments are: + +- development: `dev`, at `https://dev.ldsa-website.pages.dev/`, protected by Cloudflare Access; +- production: `main`, at `https://ldsa-website.pages.dev/` and, after cutover, the public custom domain. + +Feature branches never deploy to Cloudflare. Their changes reach the development environment only after a pull request is merged into `dev`. + +After uploading, the workflow tests the immutable deployment URL and confirms its routes, redirects, custom 404 page, security headers, indexing policy, branch and commit. It records the branch and commit in a non-cached `deployment.json` file generated only in CI. + +## 2. Create the deployment token + +Create a Cloudflare API token limited to the LDSA account with `Cloudflare Pages: Edit`. Add these GitHub Actions secrets: + +- `CLOUDFLARE_API_TOKEN` +- `CLOUDFLARE_ACCOUNT_ID` + +Optionally set the repository variable `CLOUDFLARE_PAGES_PROJECT` if the project name is not `ldsa-website`. + +Never commit tokens or put them in shell history. The workflow passes them directly from GitHub Secrets to the official Cloudflare action. + +## 3. Protect preview deployments + +In Cloudflare Zero Trust, protect preview deployments with Access. Complete the service-token steps first so GitHub Actions can continue checking the protected deployment: + +1. Open **Zero Trust → Access controls → Service credentials → Service Tokens**. +2. Create `github-actions-ldsa-preview-smoke`, choose an appropriate expiry, and copy its Client ID and Client Secret once. +3. In GitHub repository Actions secrets, add the values as `CF_ACCESS_CLIENT_ID` and `CF_ACCESS_CLIENT_SECRET`. +4. Open **Workers & Pages → ldsa-website → Settings → General**. If **Preview access** says deployments are restricted by a Cloudflare Access policy, protection is already enabled; select **Manage**. Otherwise, select **Enable access policy**. +5. In the generated `ldsa-website - Cloudflare Pages` application, keep the destination `*.ldsa-website.pages.dev`. Edit the interactive Allow policy so its Include rule contains only exact approved tester email addresses, or `Emails ending in @lisbondatascience.org` if every mailbox on that domain should have access. Remove `All authenticated users` or `Everyone`. +6. Add a second policy with action **Service Auth**, include only the `github-actions-ldsa-preview-smoke` service token, and save it. New Zero Trust organizations use strict service-token authentication, so an ordinary Allow policy is insufficient for CI. +7. Confirm the policy wildcard covers preview aliases but does not cover `ldsa-website.pages.dev` or a future production custom domain. +8. Re-run the `dev` deployment workflow and confirm the post-deployment contract check passes. +9. Open the preview in a signed-out private browser and confirm Access blocks it, then sign in as an approved tester and confirm it opens. + +The checker sends the service credentials only in Cloudflare Access request headers. Never put either value in repository variables, source files, logs, or chat. Record the token expiry and rotate the GitHub secrets before it expires. + +Cloudflare preview deployments should also send `X-Robots-Tag: noindex`. Verify the live response header before sharing the preview URL. + +## 4. Production-only observability + +Keep the Pages project's automatic **Web Analytics** switch disabled. It applies to both `dev` and `main`, which would mix private acceptance traffic into production results. + +After `www.lisbondatascience.org` is attached and selected as the canonical production hostname: + +1. In Cloudflare **Web Analytics**, create or select the site for `www.lisbondatascience.org` using the free service. +2. Copy its public site token. Do not use an API token or Access credential. +3. In **GitHub → LDSSA/website → Settings → Environments → production → Environment variables**, add `CLOUDFLARE_WEB_ANALYTICS_TOKEN` with that site token. +4. Re-run the `main` deployment. The Astro build emits the manual beacon and adds `static.cloudflareinsights.com` and `cloudflareinsights.com` only to the production artifact's CSP. +5. Confirm production loads `beacon.min.js`, sends a successful RUM request and records the controlled visit. +6. Confirm `dev` contains no beacon, no RUM request and no analytics CSP origins. + +The token is a public site identifier embedded in HTML, but keeping it in the production environment prevents accidental preview activation and centralizes configuration. Do not add visitor profiling scripts without a separate review. + +Use the Cloudflare dashboard to monitor: + +- deployment history and failures; +- Web Analytics and Core Web Vitals; +- 404 requests after cutover; +- bandwidth and cache status; +- security events. + +## 5. GitHub environments + +Create two GitHub environments: + +- `preview`: no approval requirement; restricted to `dev`. +- `production`: require an LDSA maintainer approval and restrict deployments to `main`. + +The required approval provides a final gate after online acceptance testing and before production deployment. It does not change DNS; domain cutover remains a separate controlled step. + +## 6. Custom domains + +Only after [the QA checklist](qa.md) passes, add `www.lisbondatascience.org` as the production custom domain. Authoritative DNS remains at Namecheap: change the existing `www` CNAME only after Cloudflare Pages has registered the hostname, and configure Namecheap's apex URL Redirect Record as a permanent `301` to `https://www.lisbondatascience.org/`. Follow [the DNS runbook](dns.md). Do not alter mail or domain-verification records. diff --git a/docs/operations/dns.md b/docs/operations/dns.md new file mode 100644 index 0000000..b7a6bbb --- /dev/null +++ b/docs/operations/dns.md @@ -0,0 +1,107 @@ +# DNS baseline and Namecheap cutover + +The selected architecture keeps Namecheap authoritative for `lisbondatascience.org`. Only the website records change: `www` points to Cloudflare Pages and Namecheap permanently redirects the apex to `www`. Mail, DKIM, SPF, DMARC and verification records remain at Namecheap. + +This choice does not prevent a later move to Cloudflare authoritative DNS. Before a future nameserver change, recreate and verify the complete Namecheap zone in Cloudflare, then change the nameservers. DNS records are not copied automatically when nameservers change. + +## Captured public baseline + +These values were observed on 2026-10-08. Export the authoritative Namecheap zone immediately before cutover because public DNS cannot reveal every record, particularly unknown DKIM selectors. + +| Name | Type | Value | Observed TTL | +| ------------------------------ | ----- | ---------------------------------------------------------------------- | ------------ | +| `lisbondatascience.org` | A | `192.64.119.34` | 1800 | +| `lisbondatascience.org` | A | `54.84.104.245` | 1800 | +| `www.lisbondatascience.org` | CNAME | `unbouncepages.com.` | 60 | +| `lisbondatascience.org` | NS | `dns1.registrar-servers.com.` | 1800 | +| `lisbondatascience.org` | NS | `dns2.registrar-servers.com.` | 1800 | +| `lisbondatascience.org` | MX 1 | `aspmx.l.google.com.` | 1800 | +| `lisbondatascience.org` | MX 5 | `alt1.aspmx.l.google.com.` | 1800 | +| `lisbondatascience.org` | MX 5 | `alt2.aspmx.l.google.com.` | 1800 | +| `lisbondatascience.org` | MX 10 | `aspmx2.googlemail.com.` | 1800 | +| `lisbondatascience.org` | MX 10 | `aspmx3.googlemail.com.` | 1800 | +| `lisbondatascience.org` | TXT | `v=spf1 a mx include:_spf.elasticemail.com ~all` | 1800 | +| `lisbondatascience.org` | TXT | `google-site-verification=fe3vJvPLBYVSEErYNCIPHTSrewzHJ-yopcfAyQz3OZg` | 1800 | +| `_dmarc.lisbondatascience.org` | TXT | `v=DMARC1; p=none` | 300 | + +No apex AAAA or CAA response was observed. + +## Private backup and rollback record + +Immediately before cutover: + +1. Export or manually record every Namecheap Advanced DNS entry, including A, AAAA, CNAME, MX, TXT, CAA, SRV, URL Redirect, Dynamic DNS and email-routing settings. +2. Capture every DKIM selector shown in Namecheap and the relevant mail provider. +3. Store the export and screenshots privately; never commit them if they include sensitive service details. +4. Confirm Google Workspace can send and receive mail. +5. Record the rollback values: + - `www` CNAME: `unbouncepages.com.` + - the two current apex A records shown above; + - any existing apex redirect configuration. + +## Register the Pages hostname before changing DNS + +1. Confirm the accepted `main` commit is healthy at `https://ldsa-website.pages.dev/`. +2. In Cloudflare, open **Workers & Pages → ldsa-website → Custom domains**. +3. Select **Set up a domain**. +4. Enter `www.lisbondatascience.org` and continue. +5. Keep the setup pending until Cloudflare displays the external-DNS instructions. + +Do not create the CNAME first. Cloudflare Pages requires the custom hostname to be associated with the project before the external DNS record points to it. + +## Namecheap cutover + +In **Namecheap → Domain List → lisbondatascience.org → Manage → Advanced DNS**: + +1. Change only the existing `www` record: + + | Type | Host | Value | TTL | + | ----- | ----- | ------------------------- | --------- | + | CNAME | `www` | `ldsa-website.pages.dev.` | Automatic | + +2. Configure the apex redirect: + + | Type | Host | Value | Redirect type | + | ------------------- | ---- | ------------------------------------ | ------------- | + | URL Redirect Record | `@` | `https://www.lisbondatascience.org/` | Permanent 301 | + +3. Remove only A, ALIAS, CNAME or URL Redirect records at host `@` that Namecheap identifies as conflicting with the new apex redirect. The observed apex A records are website/forwarding records, but compare them with the private zone export before removing them. +4. Do not edit MX, SPF, DKIM, DMARC, CAA, SRV or verification records. +5. Save the changes. Namecheap states that URL redirects normally begin working within about 30 minutes; resolver caches may take longer. +6. Wait for Cloudflare Pages to show `www.lisbondatascience.org` as active and for its TLS certificate to become valid. + +## Production verification + +Verify from at least two networks or public resolvers: + +1. `www.lisbondatascience.org` resolves through the Pages CNAME and serves the accepted commit over HTTPS. +2. `lisbondatascience.org` returns a permanent redirect to `https://www.lisbondatascience.org/`. +3. Deep apex URLs preserve their path when redirected. If Namecheap does not preserve paths as required, stop and replace the forwarding method before accepting cutover. +4. All maintained routes, legacy redirects, the custom 404, assets, headers, canonical URLs, `robots.txt` and the sitemap pass. +5. Flodesk submits a controlled production subscription successfully. +6. Google Workspace sends and receives controlled messages, including a reply from an external mailbox. +7. The protected `dev` alias remains separate and private. + +After the hostname is active, configure production-only Web Analytics using the Cloudflare runbook. + +## Rollback + +If production has a material failure: + +1. Restore the `www` CNAME to `unbouncepages.com.`. +2. Remove the new apex URL Redirect Record and restore the prior apex website records or forwarding configuration from the private backup. +3. Leave all mail and verification records untouched. +4. Verify the old public site and email before investigating the failed cutover. + +## Future move to Cloudflare DNS + +A future authoritative-DNS migration remains fully supported: + +1. Add `lisbondatascience.org` as a Cloudflare zone on the Free plan. +2. Import and manually compare every Namecheap record, including all mail, DKIM, SPF, DMARC, CAA, SRV and verification records. +3. Keep mail-related hostnames DNS-only where applicable. +4. Validate the staged Cloudflare zone against the private export. +5. Replace the Namecheap nameservers with the two nameservers assigned by Cloudflare. +6. Verify website, email and domain-verification services throughout propagation. + +The registrar can remain Namecheap even when Cloudflare becomes the authoritative DNS provider. diff --git a/docs/operations/github.md b/docs/operations/github.md new file mode 100644 index 0000000..55dbfdb --- /dev/null +++ b/docs/operations/github.md @@ -0,0 +1,31 @@ +# GitHub repository controls + +Apply repository rulesets to `dev` and `main` after those branches exist. + +## `dev` + +- Require a pull request with at least one approval. +- Require the `Build and verify` status check. +- Require branches to be up to date before merging. +- Require conversation resolution. +- Block force pushes and deletion. +- Allow squash merging. + +## `main` + +- Require a pull request with at least one approval. +- Require the `Build and verify` status check. +- Require branches to be up to date before merging. +- Require conversation resolution. +- Block force pushes and deletion. +- Restrict the normal merge source to `dev` through team convention. +- Protect the `production` GitHub environment with a maintainer approval. + +## Normal change flow + +```text +feature/* → pull request → dev → protected Cloudflare preview +dev → acceptance testing → pull request → main → production deployment +``` + +Dependabot checks npm and GitHub Action dependencies monthly. Dependency pull requests follow the same CI and review rules. diff --git a/docs/operations/qa.md b/docs/operations/qa.md new file mode 100644 index 0000000..4486858 --- /dev/null +++ b/docs/operations/qa.md @@ -0,0 +1,91 @@ +# Migration QA checklist + +Record the tester, date, deployed commit and result for each test. Do not use real subscriber data; use controlled test addresses owned by LDSA. + +## Automated checks + +- [ ] `npm ci` completes from the lockfile. +- [ ] `npm run check` passes. +- [ ] `npm run format:check` passes. +- [ ] GitHub Actions CI passes on the pull request. +- [ ] Lighthouse meets the repository thresholds for all five maintained routes. +- [ ] Cloudflare deployment is associated with the expected commit and branch. +- [ ] The post-deployment contract check passes against the immutable Cloudflare URL. + +## Preview access and indexing + +- [ ] Signed-out visitors cannot open the `dev` preview. +- [ ] Authorized LDSA testers can open it. +- [ ] Preview responses include `X-Robots-Tag: noindex`. +- [ ] The production candidate has a valid HTTPS certificate. + +## Routes and redirects + +- [ ] `/` +- [ ] `/starters-academy/` +- [ ] `/prep-course/` +- [ ] `/about-us/` +- [ ] `/jobs/` +- [ ] `/curriculum/` returns a 301 to `/starters-academy/#curriculum`. +- [ ] `/faq/` returns a 301 to `/starters-academy/#faq`. +- [ ] `/comms-associate-position/` returns a 301 to `/about-us/`. +- [ ] `/pythonzerotohero/` returns a 301 to `/prep-course/`. +- [ ] Recovered `*-form_confirmation.html` routes redirect to their maintained destinations. +- [ ] An unknown route renders the custom 404 page. + +## Responsive and browser coverage + +Test at 320, 375, 390, 768, 1024, 1440 and 1920 CSS pixels. + +- [ ] Chrome on desktop and Android-sized viewport. +- [ ] Firefox on desktop. +- [ ] Edge on desktop. +- [ ] Safari on macOS and iOS, when available. +- [ ] Mobile navigation opens, closes and retains keyboard focus visibility. +- [ ] There is no horizontal overflow. +- [ ] Images preserve their aspect ratio and meaningful images have useful alternative text. +- [ ] Reduced-motion preference does not introduce unusable interactions. + +## Links and integrations + +- [ ] Portal link opens the LDSA Portal. +- [ ] Wiki and course links open the correct current pages. +- [ ] GitHub, LinkedIn, Instagram, Facebook and email links work. +- [ ] YouTube video loads and can be operated by keyboard. +- [ ] Job submission guide opens correctly. + +## Web Analytics + +- [x] The private `dev` deployment contains no `beacon.min.js` request. +- [x] The private `dev` deployment contains no `/cdn-cgi/rum` request. +- [x] Cloudflare account-level request analytics remains available. +- [ ] Production loads `https://static.cloudflareinsights.com/beacon.min.js` after its environment token is configured. +- [ ] Production reports successfully without a Content Security Policy error. +- [ ] Cloudflare Web Analytics records a controlled production visit and Core Web Vitals. + +## Flodesk end-to-end tests + +Use a unique controlled address for each case, then verify the subscriber in the Flodesk account. + +- [ ] General form with only Starters Academy selected reaches the expected segment. +- [ ] General form with only Prep Course selected reaches the expected segment. +- [ ] General form with both selected reaches both expected groups. +- [ ] Starters form reaches the Starters Academy group and triggers the expected confirmation/workflow. +- [ ] Prep form reaches the Prep Course group and triggers the expected confirmation/workflow. +- [ ] Invalid email feedback is understandable and keyboard accessible. +- [ ] A successful submission shows or redirects to the intended confirmation state. + +HTTP checks prove that the public Flodesk scripts and POST endpoints exist, but only the Flodesk subscriber record can prove segment assignment and automation delivery. Do not mark this section complete from browser rendering alone. + +## Production cutover checks + +- [ ] `https://lisbondatascience.org/` redirects to the canonical `www` HTTPS hostname. +- [ ] `https://www.lisbondatascience.org/` serves the expected commit. +- [ ] Canonical and Open Graph URLs use the production hostname. +- [ ] `robots.txt` and `sitemap-index.xml` return 200. +- [ ] Security headers from `public/_headers` are present. +- [ ] Cloudflare Web Analytics records a controlled visit. +- [ ] Email delivery still works for the LDSA domain. +- [ ] Cloudflare shows no unexpected 404 or security errors. + +After all production checks pass, monitor for seven days before taking the final Unbounce backup and cancelling the subscription. diff --git a/docs/operations/release-acceptance.md b/docs/operations/release-acceptance.md new file mode 100644 index 0000000..f14a2dd --- /dev/null +++ b/docs/operations/release-acceptance.md @@ -0,0 +1,36 @@ +# Production candidate acceptance + +## Development acceptance + +- Date: 2026-10-11 +- Environment: `https://dev.ldsa-website.pages.dev/` +- Accepted functional baseline: `a6af0374b16fc27dbeeac636d95ffc1c162f388d` +- Tester/owner: `cmm79` + +The owner confirmed: + +- the preview requires Cloudflare Access; +- `info@lisbondatascience.org` can authenticate and an unapproved address is denied; +- preview responses send `X-Robots-Tag: noindex`; +- all GitHub CI and deployment checks pass; +- Pages-managed Web Analytics is disabled and the preview contains no beacon or RUM request; +- Flodesk subscription forms submit successfully and create the expected subscriber records in Flodesk. + +No subscriber addresses or other personal data are stored in this repository. + +## Release decisions + +- `main` is the production branch and `dev` is the private integration branch. +- Production DNS remains authoritative at Namecheap. +- `www.lisbondatascience.org` will point to `ldsa-website.pages.dev` only after the custom hostname is registered in the Pages dashboard. +- Namecheap will provide a permanent apex-to-`www` redirect. +- Browser Web Analytics will be enabled only for production after the final hostname is active. +- The existing Unbounce-hosted public site remains available until the DNS cutover. + +## Remaining acceptance gates + +- Promote the release-preparation changes from `dev` to `main` and verify the public Pages production hostname. +- Export the complete Namecheap zone privately and record rollback values. +- Attach `www`, complete the Namecheap cutover and verify email. +- Enable and verify production-only Web Analytics. +- Monitor production for seven days before closing the migration. diff --git a/lighthouserc.json b/lighthouserc.json new file mode 100644 index 0000000..5901d0c --- /dev/null +++ b/lighthouserc.json @@ -0,0 +1,23 @@ +{ + "ci": { + "collect": { + "staticDistDir": "./dist", + "url": [ + "http://localhost/", + "http://localhost/starters-academy/", + "http://localhost/prep-course/", + "http://localhost/about-us/", + "http://localhost/jobs/" + ], + "numberOfRuns": 3 + }, + "assert": { + "assertions": { + "categories:performance": ["error", { "minScore": 0.85 }], + "categories:accessibility": ["error", { "minScore": 0.95 }], + "categories:best-practices": ["error", { "minScore": 0.95 }], + "categories:seo": ["error", { "minScore": 0.95 }] + } + } + } +} diff --git a/migration/flodesk-inventory.md b/migration/flodesk-inventory.md new file mode 100644 index 0000000..bd414d4 --- /dev/null +++ b/migration/flodesk-inventory.md @@ -0,0 +1,20 @@ +# Flodesk integration inventory + +The live forms were recovered from rendered public HTML. Their endpoint, form ID, success mode and interest values are preserved in `src/components/FlodeskForm.astro`. + +| Purpose | Page | Form ID | Submission endpoint | Completion behavior | +| --------------------------------------- | -------------------- | -------------------------- | ---------------------------------------------------------------- | ----------------------- | +| General newsletter and course interests | `/` | `63f9e4e2f0116a4cabfef7db` | `https://form.flodesk.com/forms/63f9e4e2f0116a4cabfef7db/submit` | Inline success message | +| Starters Academy waiting list | `/starters-academy/` | `615c9641c71e8685f183bd18` | `https://form.flodesk.com/forms/615c9641c71e8685f183bd18/submit` | Redirect to site root | +| Prep Course waiting list | `/prep-course/` | `6172e62fe625581864e3f857` | `https://form.flodesk.com/forms/6172e62fe625581864e3f857/submit` | Redirect to Prep Course | + +The general form uses these Flodesk preference values: + +| Value | Label | +| --------- | ------------------------------------ | +| `option1` | Lisbon Data Science Starters Academy | +| `option2` | Data Science Prep Course | + +The Flodesk universal script progressively enhances the native forms. The component mirrors the public embed's current module/legacy loader pair, while the native `POST` action remains present as a fallback. On 2026-10-09 both public runtime files returned HTTP 200 and all three endpoints returned HTTP 405 with `Allow: POST`, confirming that the integration resources and form handlers exist without creating test subscribers. + +A real submission must still be checked against the expected Flodesk segment and automation before production cutover; rendering and HTTP-level checks cannot prove subscriber routing inside the Flodesk account. Use separate controlled LDSA addresses for each routing case in the QA runbook. diff --git a/migration/page-inventory.md b/migration/page-inventory.md new file mode 100644 index 0000000..1e23369 --- /dev/null +++ b/migration/page-inventory.md @@ -0,0 +1,29 @@ +# Public page inventory + +Captured from the public `www.lisbondatascience.org` site on 2026-10-08 and re-audited on 2026-10-09. The suspended Unbounce account cannot be inspected, so the migration scope is based on live responses, rendered source, search results, the Internet Archive CDX index, LDSA-owned public properties, and stakeholder review. + +| Current route | Unbounce page ID | Status | Migration action | Flodesk | +| -------------------------------------------- | -------------------------------------- | ---------------------------- | ----------------------------------------------------- | ---------------------------------------- | +| `/` | `7f3394ee-2bc1-4e2a-bab8-b6f82f2f95a1` | Current | Rebuilt at `/` | General form `63f9e4e2f0116a4cabfef7db` | +| `/starters-academy/` | `e32f0ae1-c188-40d7-b076-eb2635283791` | Current | Rebuilt at same route | Starters form `615c9641c71e8685f183bd18` | +| `/prep-course/` | `7fa562f1-64ad-49b9-9496-d134d3b71af0` | Current | Rebuilt at same route | Prep form `6172e62fe625581864e3f857` | +| `/about-us/` | `26c2a69c-5711-4a20-b2af-daf4908b0628` | Current | Rebuilt at same route | None | +| `/jobs/` | `19599627-f46b-430c-84cf-75e8a08edcbf` | Current | Rebuilt at same route | None | +| `/curriculum/` | `c308f178-82db-40be-a34c-14ea378e1a33` | Legacy and materially stale | Permanent redirect to `/starters-academy/#curriculum` | None | +| `/faq/` | `8e322e94-da07-418c-86fd-2aed2693fb87` | Legacy and materially stale | Permanent redirect to `/starters-academy/#faq` | None | +| `/comms-associate-position/` | `0cc074e0-cbc4-46ec-b2e2-f21e73d32b86` | Expired 2018 vacancy | Permanent redirect to `/about-us/` | Retired Unbounce form | +| `/pythonzerotohero/` | Unknown | Historical and currently 404 | Permanent redirect to `/prep-course/` | Unknown | +| Historical `*-form_confirmation.html` routes | Associated page IDs where observable | Retired confirmation pages | Redirect to the relevant maintained route | Retired Unbounce forms | + +The snapshot HTML is stored under `migration/raw/`. It is evidence and source material, not production code. It includes generated Unbounce markup and should never be copied into the final application. See `public-evidence-audit.md` for sources, response status and limitations. + +## Content decisions + +- Current course claims, open learning materials, external resources, video and contact links were retained. +- Dates, pricing and year-specific admission language that had already become stale were replaced with links to the LDSA wiki, the operational source of truth. +- The published volunteer roster was retained without mutable employer/title claims. +- Legacy Curriculum and FAQ content was consolidated into the maintained course pages so old URLs continue to resolve through 301 redirects. + +## Account-access limitation + +The account reportedly contained fourteen published pages, but its suspension prevents an account inventory, `.unbounce` backups, inactive-variant inspection, Script Manager inspection, and lead export. These items cannot be reconstructed from public responses and are no longer migration gates. LDSA accepts this limitation and will validate the publicly recovered URL set before production cutover. diff --git a/migration/public-evidence-audit.md b/migration/public-evidence-audit.md new file mode 100644 index 0000000..aad2e5b --- /dev/null +++ b/migration/public-evidence-audit.md @@ -0,0 +1,61 @@ +# Public website evidence audit + +## Scope and method + +The public LDSA site was re-audited on 2026-10-09 after the Unbounce account became unavailable. The audit used only free, public sources: + +- direct HTTPS requests to the production hostname; +- rendered HTML, scripts, forms, links, metadata and response headers; +- `robots.txt` and sitemap checks; +- public search results; +- the Internet Archive CDX URL index; +- LDSA Wiki, Portal, GitHub and social links referenced by the site; +- the existing source snapshots in `migration/raw/`. + +The live site does not expose a sitemap: `/sitemap.xml` returns 404. Its `robots.txt` only blocks Unbounce click-tracking paths. Search and archive discovery were therefore used in addition to navigation crawling. + +## Recovered route set + +| Route | Live status on 2026-10-09 | Decision | +| ---------------------------------------------------- | ------------------------------------ | ----------------------------------------- | +| `/` | 200 | Rebuilt | +| `/starters-academy/` | 200 | Rebuilt | +| `/prep-course/` | 200 | Rebuilt | +| `/about-us/` | 200 | Rebuilt | +| `/jobs/` | 200 | Rebuilt | +| `/curriculum/` | 200, materially stale | Redirect to maintained curriculum section | +| `/faq/` | 200, materially stale | Redirect to maintained FAQ section | +| `/comms-associate-position/` | 200, expired 2018 vacancy | Redirect to About/Get involved | +| `/pythonzerotohero/` | 404, historically archived | Redirect to Prep Course | +| `/d-form_confirmation.html` | 200, retired homepage confirmation | Redirect to homepage | +| `/comms-associate-position/a-form_confirmation.html` | 200, retired vacancy confirmation | Redirect to About | +| `/curriculum/a-form_confirmation.html` | 200, retired curriculum confirmation | Redirect to Starters Academy | +| `/a-form_confirmation.html` | 404, historically archived | Redirect to homepage | +| `/b-form_confirmation.html` | 404, historically archived | Redirect to homepage | + +The Internet Archive also indexed HTTP/HTTPS and port variants of these URLs. Those are hostname/protocol variants rather than separate content routes. + +## Public integration findings + +Three Flodesk forms are present in the rendered production HTML: + +| Page | Form ID | Endpoint | +| ---------------- | -------------------------- | ---------------------------------------------------------------- | +| Homepage | `63f9e4e2f0116a4cabfef7db` | `https://form.flodesk.com/forms/63f9e4e2f0116a4cabfef7db/submit` | +| Starters Academy | `615c9641c71e8685f183bd18` | `https://form.flodesk.com/forms/615c9641c71e8685f183bd18/submit` | +| Prep Course | `6172e62fe625581864e3f857` | `https://form.flodesk.com/forms/6172e62fe625581864e3f857/submit` | + +The homepage form sends the public preference values `option1` for Starters Academy and `option2` for Prep Course. The public embed loads `https://assets.flodesk.com/universal.mjs` for modern browsers and `https://assets.flodesk.com/universal.js` as the legacy fallback. Both resources returned HTTP 200 on the audit date. Each form endpoint advertised POST support without a test submission. + +The public HTML also contains the old Google Analytics property `UA-113478482-1`, Unbounce runtime code, old jQuery code, YouTube, and normal outbound links. No Google Tag Manager, Meta Pixel, or LinkedIn Insight Tag was observed. + +## Accepted limits + +Public evidence cannot reveal unpublished pages, inactive experiment variants, disabled global scripts, lead records, historical analytics, or server-side integrations that produce no browser-visible effect. These unknown account-only items are accepted as unavailable and do not block migration. Production acceptance is based on: + +- all recovered routes and redirects; +- maintained public content and metadata; +- visual and responsive QA; +- external-link checks; +- real Flodesk subscriber-routing tests; +- stakeholder review before DNS cutover. diff --git a/migration/raw/.gitkeep b/migration/raw/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/migration/raw/.gitkeep @@ -0,0 +1 @@ + diff --git a/migration/raw/about-us.html b/migration/raw/about-us.html new file mode 100644 index 0000000..32ac677 --- /dev/null +++ b/migration/raw/about-us.html @@ -0,0 +1,3812 @@ +
+ + +We are a group of Data Scientists and volunteers, from all kind of organisations, who absolutely love to teach and spread the knowledge of Data Science and its amazing uses!
The Academy is not for profit and all fees are re-invested into the program, to continuously make it better.
© 2020 Lisbon Data Science Academy.
All rights reserved
Get in touch!
info@lisbondatascience.org
© 2022 Lisbon Data Science Academy. All rights reserved
BySofiaDesign
President
Vice-President
Vice-President
+We need help spreading the word about the Academy and managing our social presence, including some content creation. For this we need someone passionate about bringing affordable tech education to students and professionals, someone with fresh ideas and a willingness to learn, but teach too. +
++Lisbon Data Science Academy is a non-profit, volunteer-based organisation bringing affordable education to students and tech professionals. We are proud to say that amongst our volunteers we have a few of the best data scientist in Portugal, successful entrepreneurs, engineers, founders, CEOs and CTOs. +
++Last year we ran the first data science course in Portugal. It was a great success and an amazing experience for the whole team, where we got to work with industry leaders such as Microsoft, Farfetch, Uniplaces. +
++This year we’re set on providing an even better experience for our students and expanding our network of partners even further. That’s where you come in! +
++In return we offer over 200 years of our cumulative experience in the tech industry. +
++You will be part of all our weekly meetings and will be able to see first hand the inner workings of an educational startup. +
++You will have a voice in building the Lisbon Data Science Academy brand +
++You’ll become a part of our Mastermind and make friends for life +
++You’ll increase your network with people from startups and tech companies. +
++We will add you as a collaborator in our LinkedIn organisation and write a recommendation that might just be the tipping point towards hiring for your next clients. +
+
+
+
+This positions will be open from now until September 2018. +
++It will require around 5 hours per week in the first 2 months and between 2 and 4 hours per week after that. +
++Once a month, you’ll need to attend our hackathons for few hours (always a Sunday). Locations and dates are to be decided, but previous locations included the Lisbon offices of Microsoft, Farfetch, Uniplaces and Outsystems, to name a few. +
++Digital marketing +
++Social media management +
++Content creation +
++Community management +
++Excellent written and spoken English (CAE preferred) +
++Strong organizational skills +
++Command of Google Apps tools (Gmail, Calendar, Google Docs, Google Sheets) +
++Good communication skills and enthusiasm for working with people +
++Enthusiasm for technology +
++Experience in communication positions +
++Photography skills +
+
+Video editing skills
+
+
+
+The Bootcamp
+
+
+
+6th & 7th July +
++The Bootcamp +
++21st July +
+
+Hackathon #1
+
+25th August +
++Hackathon #2 +
++29th September +
++Hackathon #3 +
++27th October +
++Hackathon #4 +
++24th November +
++Hackathon #5 +
++The Starters Academy lasts approximately 21 weeks (~ 7 months). Of that time, 8 days are in-person (usually on Sundays), and the rest is done remotely via GitHub, Slack and the Academy's submission and grading system. +
+
+ Hackathon #1
+
+ Hackathon #2 +
+
+
+
Hackathon #3
+
+ Hackathon #4 +
++ Hackathon #5 +
+
+
+
6th & 7th
+
+July
+
+
+
21st
+
+July
+
+
25th August
+
+
29th September
+
+
27th October
+
+
+
24th
+
+November
+
+BOOTCAMPS +
++The Bootcamp is an intensive, 2 day event, where students and teachers will be in the same building for 10 hours per day, and the students will go through their first 20 Learning Units. +
+
+
+
+HACKATHONS +
++Hackathons are longer and less structured exercises, often done in teams, in which the students must complete a relatively advanced project. Hackathons require the students to make use of the skills they learned in the Learning Units, but also to excel at teamwork and communication. +
++© 2018 Lisbon Data Science Academy. +
++All rights reserved +
++Get in touch! +
++info [at] lisbondatascience.org +
++© 2018 Lisbon Data Science Academy. All rights reserved +
++Amazing community and very knowledgeable instructors! +
++ I entered the academy with some previous knowledge, but it was nowhere near to what I learned throughout the first edition. The learning materials were adequate and simple to learn in order to face the monthly hackathons. The hackathons were super challenging and in awesome places. Oh and food / drinks / coffee in the hackathons were never a problem, so the logistics were great! +
++“ +
++This image shows a high level overview of the learning units. +
+
+You can see the curriculum in more details in this document.
+
+Sign up for our mailing list to receive information about our next batch first-hand
+
+1 - What do you mean by strong quantitative skills? +
++You should be comfortable around numbers, quickly understanding a real life problem and translate it into something measurable & workable. Usually is the kind of skills that results from having an education or working experience in the fields of (but not only) Engineering, Physics, Mathematics, Management, Economics, etc.. +
++ +
++2 - Will I have any kind of teaching support, if I need, during the months following the Bootcamp Days? +
++Definitely yes! This is one of the strongest things we want to build during the Academy experience: the community effect! We are working hard to make sure you have access to a community of colleagues, teachers and staff that will be there to help you in whatever way it's possible. Even you will be able to help others! +
++ +
++3 - Is there any financial support if I can't afford the student fees? +
+
+We are in the process of deciding this. Please check this page soon.
+
+ +
++4 - What will be the size of the students group? +
++We are expecting a maximum of 50 students. The idea is to have a high teacher-student ratio, and to ensure everyone gets enough support. +
++ +
++5 - Are meals included in the fee? +
++Yes, lunch and snacks during the day. +
++ +
++6 - Will there be any kind of internship possibility at the end of the school? +
++We are working hard to surprise you on this topic. More news will come soon. +
++ +
++7 - What language will the classes be held in? +
++English. +
++ +
++8 - Will you teach python? +
+
+Yes but enrolments for the Data Science Prep Course for Batch 3 are now closed.
+
+Want to enrol next time? Subscribe here to our newsletter to stay updated on all new dates!
+
+ +
++9 - I don’t know any data science, will I be able to do the classes? +
++Yes! The classes are directed at people who are giving their first steps in the data science world. +
++ +
++10 - I can come to the Bootcamp days, but can’t make it to the hackathons. Should I apply anyway? +
+
+Presence in the bootcamp and Hackathon #1 is compulsory, as is the capstone.
+
+Of hackathons 2 through 5, you are allowed to do one remote if the need is justified, and (if you really, really have to) miss one.
+
+
+
+11 - Will laptops be provided?
+
+No, you must bring your laptop with you +
++ +
++12 - When will we install the necessary software? +
++Setup must be done before arrival, we will provide step by step instructions, and remote support. +
+
+
+
+13 - Do you have a refund policy? +
+
+Sorry, since the payment and course start dates are so close, we're not doing refunds.
+
+
+
+14 - How do I know if my python skills are good enough? +
++A good option would be doing our test. In case you want to know, the main topics we cover on this test are the following: +
+
+- if and else statements
- for loops
- handle arrays and tuples (including slicing)
- handle lists and dictionaries (including list comprehension)
- string manipulation
- data types (like int, float, string and how to convert variables between them)
- define and use functions
- lambda functions and map
- try except statements
- basics of OOP (like what's a class, how to instantiate one and use methods from the class)
+
+© 2018 Lisbon Data Science Academy. +
++All rights reserved +
++Get in touch! +
++info [at] lisbondatascience.org +
++© 2018 Lisbon Data Science Academy. All rights reserved +
+Data Scientists are one of the most required and highly paid professionals today. They swim in the heaps of data our society generates and make discoveries that drive business decisions. It’s been called the coolest profession of the 21st century.
The LDSA is a non-profit organization dedicated to Data Science, 100% run by volunteers. It is responsible for the Data Science Starters Academy which focuses on introductory material for those who want to become entry-level data scientists.
Take a look at six months of work and fun in 150 seconds.
If you're completely new to programming and software engineering, you're not ready for the Starters Academy yet.
But we've got you covered! In the Prep Course you can learn all the basics you need, as a first step in you data science journey.
An introductory course to the Data Science field where you'll learn all the skills needed to become a junior data scientist. It lasts for ~7 months and it's designed so that it doesn't interfere with your day job.
Due to the COVID-19 pandemic, this year's batch will be remote.
Starters Academy
Prep Course
Starters Academy
Prep Course
Get inside our newsletter and we'll send you all the LDSA goodies first-hand at the right time.
(news about Free Data Science Prep Course, Starters Academy, etc)
Just LDSA news - we hate SPAM too.
Sign-ups are open until 11.59 pm on June 20th.
Before signing up, please check all information about the application process here: https://ldssa.github.io/wiki/Applicants/Application-process/
Subscribe to our newsletter to get the latest news
when the admissions open.
© 2020 Lisbon Data Science Academy.
All rights reserved
Get in touch!
info@lisbondatascience.org
© 2022 Lisbon Data Science Academy. All rights reserved
(yes, both for you and for the applicant)
© 2020 Lisbon Data Science Academy.
All rights reserved
Get in touch!
info@lisbondatascience.org
© 2022 Lisbon Data Science Academy. All rights reserved
Prep Course applications start
18th March
Prep Course applications start
26th March
Accepted students are announced
5th April
Prep Course starts
To be announced
Starters Academy applications start
18th June
Prep Course ends
The Prep Course was designed as a preparation for the Starters Academy. It is fully taught online and lasts for 12 weeks.
You'll learn how to program in Python, how to use the command line, some linear algebra basics and version control with git.
Accepted students are announced
Prep Course starts
Starters Academy applications start
Prep Course ends
2021-03-18
2021-03-26
2021-04-05
To be announced
2021-06-18
© 2020 Lisbon Data Science Academy.
All rights reserved
Get in touch!
info@lisbondatascience.org
© 2022 Lisbon Data Science Academy. All rights reserved
Before the preparation course I was very rusty in Python, not having programmed anything in over a year. The course gave me the foundations that allowed me to ace the entrance test and ensured that, throughout the academy, the “how should I put this idea into code?” problem never really existed. I highly recommend it!
“
Updated curriculum will be announced soon.
00
0. I want more information!
Check the Wiki: https://ldssa.github.io/wiki/
1. What is the LDSA Prep Course about?
The Prep Course was designed to teach you everything you need to know before joining the Data Science Starters Academy. It was created to be taken 100% remotely. This means that it's fully taught online, with new content every week, and instructors available to help you.
2. What topics are covered?
We start by teaching you how to program in Python. We'll then go through some Linear Algebra basics and we'll show you how to translate them into coding using Numpy. We'll also cover some software development utilities like how to use the command line, using a text editor for programming, version control with git and Python modules, and packaging. We'll wrap it up with a final project where you'll be putting everything you've learned into practice.
3. When does the course start?
The more news on this soon. Subscribe to our newsletter on our main page to receive the news firsthand.
4. How much does it cost?
The Prep Course is free for everyone!
5. What is the recommended time commitment?
If you have no prior knowledge of any of the subjects, you should be prepared to spend an absolute minimum of 10 hours per week on the course. We understand this might sound like a lot. However, this course was not designed to give you some brief ideas on Python programming. Instead, we expect that you will fully grasp all fundamental concepts and practice enough to instinctively solve programming problems. If you already have a certain degree of knowledge of some topics, we expect the time required will be less. Finally, keep in mind that this recommendation does not include the preparation time for the admission test for the Starters Academy.
6. Is there any software/app I need to be able to do the course?
Yes, there is some software you’ll need to install, but we will provide you with detailed guidelines on how to do it. This requires you to have a computer/laptop with admin rights.
7. How does the application process work?
Once you sign up, we will share with you the application form. You will need to answer all of the questions, which will be evaluated to decide whether you will be accepted. Keep in mind that we will not test any technical or prior knowledge. This is for us to assess your motivation and whether you will be to undertake an accelerated learning experience. Dates about applications will be disclosed soon.
8. By doing the course, do I have a 100% chance to get into the Lisbon Data Science Starters Academy?
No, doing or completing the course does not guarantee you a slot in the Academy. What we are confident to say is that doing the course will increase your chance to get in. Last year, out of 50 people who got accepted into the Academy, 25 people went through the prep course, and many of them had never been exposed to programming before.
9. I’m an absolute n00b. Will I be able to do the Prep Course?
This course is designed for people without any prior knowledge or experience in the field. This is our diversity effort to enable everyone to enter the amazing world of Data Science.
10. Will I get a certificate at the end?
Not at this time. However, we are sure that, more than the certificate you could get, your biggest takeaway from this course will be the knowledge you've acquired and how it will help you navigate the world of Data Science.
We kindly remind you that - although most of our students are able to successfully find a job in Data Science - we can't guarantee it will actually land you a job and a career in tech. Additionally, the Starters Academy was designed to be taken as a sidekick, not your main activity.
Applications will open in Jan-Feb 2026.
Subscribe to our newsletter to get the latest news.
Master the basics of Python, along with some Git and Numpy and some good old-fashioned puns!
Fill out your application today and we’ll send the results in a few days to let you know if you’re in.
This is what you’ll learn: Python Programming, NumPy, the *nix command line, Git Basics, Jupyter, Linear Algebra.
LEARNING UNITS WITH EXERCISES
During the first 10 weeks, you'll develop software engineering skills using our learning materials and testing them with our auto-graded exercises.
You'll be in touch with instructors and other students attending the course, so that you can give or ask for help anytime!
FINAL PROJECT
In the final project, you'll put all those new skills in practice, and build a piece of software that you'll definitely be proud of.
It is all about interaction, growth and experience, so you can confidently build up your data science skills.
The Starters Academy lasts approximately 40 weeks of part-time work over the course of 8 months.
Of that time, there are 9 days where we request you to be virtually present (usually on Sundays), and the rest is done remotely via GitHub, Slack, and the Academy’s grading and submission system.
You should be prepared to spend a recommended 10 hours per week on the course and an absolute minimum of 5 hours per week in case you are having a busy week.
You do not need to quit your primary responsibility to take part in this course.
BOOTCAMP
During the Bootcamp, the students and teachers will participate virtually in a series of presentations and exercises, about 10 hours per day, and the students will go through 16 Small Learning Units.
SPECIALIZATIONS
After the bootcamp, there will be 5 remote Specializations, that are deeper dives into different areas in Data Science. Each lasts for a month and ends with an hackathon where students and instructors get together online.
This image shows a high-level overview of the learning units for Batch 5.
This curriculum is subject to change without further notice.
Subscribe to our newsletter to get the latest news
when the admissions open.
The Data Science Starters Academy is a series of events dedicated to helping people become entry-level data scientists, by teaching introductory material.
Data Scientists are one of the most required and highly paid professionals today.
They swim in the heaps of data our society generates and make discoveries that drive business decisions.
It’s been called the coolest profession of the 21st century.
It's a 100% online and remote course. Meaning that is a way of learning that doesn’t interfere with your day job.
We start with a two-day intensive synchronous remote bootcamp and then we get together once a month for a synchronous remote hackathon. In between hackathons you’re provided with materials to study in your own time, with support from top-level mentors on slack.
The academy is aimed at students or professionals with little to no knowledge of data science, but with strong quantitative skills and knowledge of software development in Python. If you are one of these, join us!
The Academy is taught by top data scientists from leading companies such as Farfetch, Feedzai, Google, Spotify, Unbabel and many others.
They volunteer their time at the Academy to help brilliant students like you.
This will be your first step towards becoming a Data Scientist!
By the end of the Academy you will have skills to start a career in data science, and an amazing toolkit to learn more advanced subjects.
HACKATHONS
Hackathons are longer and less structured exercises, done in teams, in which the students must complete a relatively advanced project. Hackathons require the students to make use of the skills they learned in the Specializations, but also to excel at teamwork and communication.
CAPSTONE PROJECT
The Capstone Project is the students' first solo flight. They'll consolidate everything they've learned in the Academy by working on a project designed to be a real-life data science project
STUDENTS
250€
We're giving a 50% discount to all students who'll provide a valid student ID
REGULAR
500€
Invest in a game-changer subject for a fraction of its real cost
COMPANIES
1500€
Bring data science into your company through existing employees who already have institutional knowledge
1. What do I need to know before applying to the Starters Academy?
You need to know how to program in Python and have basic software engineering skills, like being able to use the command line, being familiar with git and GitHub, and using a text editor to write code. You should also know some linear algebra basics and have used Numpy before.
You can check our Data Science Prep Course Wiki Page and GitHub repo to learn or remind yourself of all these topics.
2. You also say that students should have strong quantitative skills. What does this mean?
You should be comfortable around numbers, quickly understanding a real life problem and translate it into something measurable & workable. Usually these are the kind of skills that result from having an education or working experience in the fields of (but not only) Engineering, Physics, Mathematics, Management, Economics, etc..
3. Will you teach Python at the Starters Academy?
No. Knowing Python is actually a requirement to join the Starters Academy. But if you don’t know how to program in Python, you can check our Data Science Prep Course, that was designed to teach you everything you need to know for the Starters Academy.
4. I don’t know any data science, will I be able to do the classes?
Yes! The classes are directed at people who are giving their first steps in the data science world.
5. How does the admission process for the Starters Academy work?
The first step is to apply to the Starters Academy, during the applications phase. If you subscribe to our waiting list, you’ll receive an email with instructions for this when the time comes.
Then, during the test phase, you’ll have to solve a timed coding test and go through some introductory data science materials with exercises.
If you pass the test phase, you’ll be eligible to join the Starters Academy. We’ll take all the applicants who passed the test phase and randomly select the students for the Starters Academy. According to last year’s numbers, if you pass the test phase, you’ll have about a 50% probability of being selected.
If you’re selected, you’ll have 48 hours from the moment you received your acceptance email, to pay the admission fee and formally become a student of the Starters Academy!
Before applying, read the full details on the admission process here.
6. How do I know if my Python skills are good enough?
A good option is to apply and give the admission coding test a try. If you pass, it means that you know enough! :) In case you want a more detailed list of topics, check the Data Science Prep Course curriculum. The coding test will evaluate all these topics.
7. What will be the size of the student group?
We accept a maximum of 50 students in each edition of the Starters Academy. This year, due to the COVID-19 pandemic, we added an extra 10 seats for scholarships. If not filled, they will be converted to regular seats.
If you need a scholarship, you can learn how to apply here.
8. Will I have any kind of teaching support, if I need it, during the months following the Bootcamp Days?
Definitely yes! This is one of the strongest things we want to build during the Academy experience: the community effect! We are working hard to make sure you have access to a community of colleagues, teachers, and staff that will be there to help you in whatever way it's possible. Even you will be able to help others!
9. Is there any financial support if I can't afford the student fees?
Yes! If you want to apply to one of our scholarships, please check out our wiki page for more details.
10. Do you have a refund policy?
Please check our wiki here about this topic.
11. Will there be any kind of internship possibility at the end of the school?
We are working hard to surprise you on this topic. More news will come soon.
12. I can participate on the Bootcamp days, but can’t make it to the hackathons. Should I apply anyway?
Online presence in the Bootcamp and Hackathon #1 is compulsory.
For Hackathons #2 to #6, you are allowed to miss a hackathon (but you’ll still have to deliver it later).
Delivering the Capstone Project is also mandatory.
13. What language will the classes be held in?
English.
14. Are laptops provided?
No, you must bring a laptop with you, with at least 8GB of RAM.
If you’re planning on bringing your company’s laptop, make sure you have admin rights, because you’ll need to install some software.
15. When will we install the necessary software?
Setup must be done before arrival, we will provide step-by-step instructions and remote support.
16. Will batch 5 be 100% remote?
Yes, all teaching and mandatory events will be held online. But optional meetup, or conference, or social events will be organized in Lisbon.
17. I’m not based in Portugal. Can I participate?
Yes! Since we’ll be going remote, this year’s batch is location-independent. However, all synchronous events will be held in the Portuguese timezone (WET). You need to attend these events at the time they are happening, regardless of where you are.
18. Are there any restrictions on the selection criteria?
Yes. Although we randomly select students that passed the coding test and practical exercises, we have a few (important) restrictions. More details on that can be found here.
19. Will I receive a certificate?
If you successfully accomplish all requirements for graduation, then yes. Although we believe the learning is bigger than a certificate, we'll be providing one. The expected timeframe for certificate delivery is between 1 to 3 months after graduation.
20. I would like to check more information. Where can I check it?
Great question! Our absolute source of truth for the entire organization is our wiki. We strongly recommend that, before applying, that you check our wiki here.
21. Are the materials only accessible to students inside the Starters Academy?
No. We are advocates for open-source materials and you can find our materials in our GitHub repo (come back for updates on the link). You are free to follow the materials of the course independently but won't be able to attend the Bootcamp, hackathons, capstone, and have access to the instructors. And be part of an amazing community!
22. What is the required time commitment?
For that information (and other relevant ones), please refer to our wiki page.
We kindly remind you that - although most of our students are able to successfully find a job in Data Science - we can't guarantee it will actually land you a job and a career in tech. Additionally, the Starters Academy was designed to be taken as a sidekick, not your main activity.
28th May
Applications start
28th June
Accepted students are announced
18th & 19th July
Bootcamp
2nd August
Hackathon #1
30th August
Hackathon #2
27th September
Hackathon #3
25th October
Hackathon #4
22nd November
Hackathon #5
10th January
Hackathon #6
For this Batch, we are reserving 10 spots for scholarships for people that are in a no/low-income situation. If you are in this situation and interested to enroll at the Starters Academy, read about how to apply for a scholarship here
If granted, the pricing for scholarships is a symbolic fee of 20€.
For Batch 5, we are reserving 10 spots for scholarships for people that are in a no/low-income situation.
If you are in this situation and interested to enroll at the Starters Academy, read about how to apply for a scholarship here.
If granted, the pricing for scholarships is a symbolic fee of 20€.
Join our mailing list to receive all news firsthand for the next edition of the Starters Academy
Before applying, make sure that you visit our wiki to find all the updated information regarding the Starters Academy.
LDSSA is an incredible experience if you are starting out in Data Science. I worked in the industry already and found the Academy very valuable to review foundations and meet new people with the same interests and in the same field. The course was very hands-on with real world explanations and problems and, more importantly, messy data! The final project was very interesting in the sense that we needed to solve a real problem scenario, given by an hypothetical client. We had to do everything from defining the project scope, building an acceptable solution given a series of constraints, deploying it in the cloud through an API and building a final report in order to present our solution and approach to the client. I have fine-tuned my knowledge in the area (pun intended) and at the same time I met a very friendly and determined group of instructors alongside some colleagues who are now great buddies. It's very rewarding to build something from the ground up and making it accessible for everyone to use!
“
I’ve been working as a software engineer and was looking for a career change for more than a year, going through LDSA (Starter Academy) was something that I was thinking a lot of. At first, I wasn’t sure that a fully online course with high requirements would be possible (even to me, a developer) to make it out, but I've learned so much and met a lot of incredible people! And now I'm getting, even more, closer to achieve my goal of becoming a Data Scientist! Thank you so much! LDSA you are Amazing!
“
Istarted LDSA after my Master's in Data Science and Advanced Analytics. It really consolidated my knowledge in Data Science and added Recommender Systems and Time Series to my repertoire.
I loved how well structured the course was, how much depth it went into and the specialised hackathons challenged us to put the new knowledge into practice straight away. I am inspired by the quality of the material, the dedication of the teachers and the commitment of the fellow students. It was not an easy undertaking, but it's worth every ounce of effort you put in.
“
Istarted LDSA after my Master's in Data Science and Advanced Analytics. It really consolidated my knowledge in Data Science and added Recommender Systems and Time Series to my repertoire.
I loved how well structured the course was, how much depth it went into and the specialised hackathons challenged us to put the new knowledge into practice straight away. I am inspired by the quality of the material, the dedication of the teachers and the commitment of the fellow students. It was not an easy undertaking, but it's worth every ounce of effort you put in.
“
LDSSA is an incredible experience if you are starting out in Data Science. I worked in the industry already and found the Academy very valuable to review foundations and meet new people with the same interests and in the same field. The course was very hands-on with real world explanations and problems and, more importantly, messy data! The final project was very interesting in the sense that we needed to solve a real problem scenario, given by an hypothetical client. We had to do everything from defining the project scope, building an acceptable solution given a series of constraints, deploying it in the cloud through an API and building a final report in order to present our solution and approach to the client. I have fine-tuned my knowledge in the area (pun intended) and at the same time I met a very friendly and determined group of instructors alongside some colleagues who are now great buddies. It's very rewarding to build something from the ground up and making it accessible for everyone to use!
“
I’ve been working as a software engineer and was looking for a career change for more than a year, going through LDSA (Starter Academy) was something that I was thinking a lot of. At first, I wasn’t sure that a fully online course with high requirements would be possible (even to me, a developer) to make it out, but I've learned so much and met a lot of incredible people! And now I'm getting, even more, closer to achieve my goal of becoming a Data Scientist! Thank you so much! LDSA you are Amazing!
“
I started LDSA after my Master's in Data Science and Advanced Analytics. It really consolidated my knowledge in Data Science and added Recommender Systems and Time Series to my repertoire.
I loved how well-structured the course was, how much depth it went into and the specialised hackathons challenged us to put the new knowledge into practice straight away. I am inspired by the quality of the material, the dedication of the teachers and the commitment of the fellow students. It was not an easy undertaking, but it's worth every ounce of effort you put in.
“
© 2020 Lisbon Data Science Academy.
All rights reserved
Get in touch!
info@lisbondatascience.org
© 2022 Lisbon Data Science Academy. All rights reserved
Signups
17th June to 30th June
1st July to 21st July
Test & SLU
22nd July
Candidates Selection
23rd to 27th July
Payments & scholarship interviews
23rd to 28th September
Hackathon #1
20th October 2024
Hackathon #3
Capstone Project
Setup and Introduction
17th November 2024
Hackathon #2
15th December 2025
2nd February 2025
Hackathon #4
2nd March 2025
Hackathon #5
30th March 2025
Hackathon #6
7th April to 15th June 2025
+
+
+
+ 404
+Try the homepage, browse one of our courses, or email the LDSA team if an old link brought you here.
+ Return home +About LDSA
+We are a volunteer community from many organisations and backgrounds, united by the belief that excellent data science education should be practical, open and welcoming.
+
A non-profit learning community
+LDSA is run by volunteers. Course fees support the programme and its learners, helping us improve materials, teaching, access and the community around them.
+Our instructors and organisers bring experience from research, startups, consultancies, public institutions and technology companies. What connects them is a willingness to share what they know.
+People over the years
This migration preserves the volunteer roster published on the previous website. Roles and employers change over time; the shared contribution to LDSA is what matters here.
Get involved
+Teaching, mentoring, reviewing materials, organising events and supporting operations all make the Academy possible.
+ Talk to the team +Learn together. Build in public.
+LDSA is a volunteer-run, non-profit academy. We help motivated learners build the practical skills and support network needed to enter data science.
+ +
+ 100% powered by volunteers
+Why LDSA
Data science is easier to learn when you are surrounded by people solving the same hard problems. LDSA combines open materials, demanding projects, experienced mentors and a community that stays with you.
+Work through focused learning units, exercises, hackathons and an end-to-end capstone project.
Ask questions, review work and grow with peers, instructors and mentors from the data community.
Our learning materials are public, so anyone can use them and contribute improvements.

Choose your starting point
+If Python and software development are new to you, begin with the free Prep Course. If you already have those foundations, the Starters Academy takes you through the core skills of an entry-level data scientist.
+Build confidence with Python, NumPy, Git, the command line and linear algebra.
Start with the Prep Course →Develop job-ready foundations through structured study, team hackathons and a capstone project.
Explore the Starters Academy →Reach the LDSA community with a relevant opportunity. Publishing a job is free for organisations and applicants.
Offer a job →A glimpse of the Academy
+See how the first LDSA batch learned, built projects and became a community.
+Jobs for the LDSA community
+Share a relevant role with learners and alumni who have practised solving real data problems in a demanding, collaborative programme.
+ Read the publishing guide (opens in a new tab) +How it works
LDSA’s wiki explains the current submission format and publishing process. There is no charge to the organisation or applicant.
Data science, analytics, machine learning and related early-career roles are the best fit for the community.
Include a clear role description, location or remote policy, requirements, compensation where possible, and how to apply.
Follow the contact route in the guide so volunteers can review and share the opportunity.
Why this community
+LDSA projects involve ambiguous data, teamwork, communication and delivery. The community includes career changers, working professionals and volunteers from across the data ecosystem.
+ Start with the job submission guide → (opens in a new tab) +Data Science Prep Course
+A free, fully online course for beginners. Learn Python, NumPy, Git, the command line and essential linear algebra with support from the LDSA community.
+ See the current course details (opens in a new tab) +Start from zero
+The Prep Course teaches the practical programming and software foundations expected when applying to the Starters Academy. It is remote, hands-on and paced over several weeks.
+New learning units arrive regularly, with exercises, instructors to ask for help and a final project that puts the pieces together.
+What you will learn
These foundations help you work independently, understand course materials and tackle the Starters Academy admission exercise with confidence.
Variables, control flow, functions, collections, modules and object-oriented basics.
Work with arrays and translate essential mathematical ideas into code.
Use the Unix command line, Git, GitHub, editors, notebooks and Python packaging.
How it works
Study new material, practise with auto-graded exercises and ask instructors or peers when you get stuck.
Combine your new skills in a practical piece of software you can explain and be proud of.
Questions
The official wiki contains the latest schedule and admissions information for each edition.
Data Science Starters Academy
+A structured, part-time programme built around open materials, monthly challenges, close support and the kind of messy problems data scientists solve at work.
+ Read the application guide (opens in a new tab) +What it is
+The Academy is for students and professionals with little or no data science experience, strong quantitative skills, and working knowledge of Python and software development.
+The programme runs remotely through GitHub, Slack, synchronous teaching and LDSA’s grading system. Learners should plan for roughly 10 hours of work each week.
+ Need the Python foundations first? Meet the Prep Course → +The format
Each stage adds more independence. You begin with shared foundations and finish by owning a complete data science project.
An intensive synchronous start with presentations, exercises and the first learning units.
Focused learning units develop core data science skills, with mentor support between live events.
Teams apply what they learned to ambiguous projects that require technical work, communication and judgement.
A solo, end-to-end project that brings together problem framing, modelling, engineering and communication.
Instructors, staff and peers help unblock the hard parts and keep learning moving.
Course materials remain available to independent learners and future contributors.

Curriculum
The exact units evolve with each batch. The official wiki is the source of truth for the current curriculum.
Work with real datasets, clean imperfect inputs and communicate what the data says.
Build, validate and explain models with sound experimental habits.
Go deeper into selected areas through focused learning and project work.
Turn analysis into a reproducible result and explain decisions to technical and non-technical audiences.
Questions
Dates, fees and selection details can change between editions. For batch-specific information, follow the official application guide.